wallet work.

This commit is contained in:
Christopher Jeffrey 2016-06-27 03:07:43 -07:00
parent b8997c9212
commit ae7bbeb065
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 321 additions and 175 deletions

View File

@ -181,6 +181,7 @@ function Environment(options) {
this.wallet = require('./wallet');
this.account = this.wallet.Account;
this.walletdb = require('./walletdb');
this.path = this.walletdb.Path;
this.provider = this.walletdb.Provider;
this.peer = require('./peer');
this.pool = require('./pool');

View File

@ -110,178 +110,6 @@ TXDB.prototype._testFilter = function _testFilter(addresses) {
return false;
};
// Each address can potentially map to multiple
// accounts and wallets due to the fact that
// multisig accounts can have shared addresses.
// An address could map to 2 accounts on different
// wallets, or 2 accounts on the same wallet!
// In summary, bitcoin is hard. Use Bobchain instead.
//
// Table:
// [address-hash] -> [array of Path objects]
// '1edc6b6858fd12c64b26d8bd1e0e50d44b5bafb9':
// [Path {
// id: 'WLTZ3f5mMBsgWr1TcLzAdtLD8pkLcmWuBfPt',
// name: 'default',
// account: 0,
// change: 0,
// index: 0
// }]
//
// What we need:
// Table: Above.
// All: uniqified paths by id/name
// Outputs: Technically uniqified by ID, but id/name works too.
// What they need (api):
// outputs: [
// // Sum of value:
// { value: 0, id: wallet-id, name: account, index: account }
// ]
function WalletMap(table) {
var i, j, keys, key, paths, path;
this.inputs = [];
this.outputs = [];
this.paths = [];
this.accounts = null;
this.wallets = [];
this.table = null;
keys = Object.keys(table);
// Flatten paths and push all of
// them onto the `paths` array.
for (i = 0; i < keys.length; i++) {
key = keys[i];
paths = table[key];
for (j = 0; j < paths.length; j++) {
path = paths[j];
this.wallets.push(path.id);
this.paths.push(path);
}
}
this.wallets = utils.uniq(this.wallets);
this.accounts = uniq(this.paths);
this.table = table;
}
WalletMap.fromTX = function fromTX(table, tx) {
var map = new WalletMap(table);
var i, input, output;
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
map.inputs.push(MapMember.fromMember(table, input));
}
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
map.outputs.push(MapMember.fromMember(table, output));
}
return map;
};
WalletMap.prototype.hasPaths = function hasPaths(address) {
var paths;
if (!address)
return false;
paths = this.table[address];
return paths && paths.length !== 0;
};
WalletMap.prototype.getPaths = function getPaths(address) {
return this.table[address];
};
WalletMap.prototype.toJSON = function toJSON() {
return {
inputs: this.inputs.map(function(input) {
return input.toJSON();
}),
outputs: this.outputs.map(function(output) {
return output.toJSON();
}),
paths: this.paths.map(function(path) {
return path.toJSON();
}),
accounts: this.accounts.map(function(path) {
return {
id: path.id,
name: path.name,
account: path.account
};
}),
wallets: this.wallets
};
};
function MapMember() {
this.value = 0;
this.address = null;
this.paths = [];
this.accounts = [];
this.wallets = [];
}
MapMember.prototype.toJSON = function toJSON() {
return {
value: utils.btc(this.value),
address: this.address
? this.address.toBase58()
: null,
hash: this.address
? this.address.getHash('hex')
: null,
paths: this.paths.map(function(path) {
return path.toJSON();
}),
accounts: this.accounts.map(function(path) {
return {
id: path.id,
name: path.name,
account: path.account
};
}),
wallets: this.wallets
};
};
MapMember.fromMember = function fromMember(table, io) {
var address = io.getAddress();
var member = new MapMember();
var i, paths;
member.value = io.coin
? io.coin.value
: io.value || 0;
if (!address)
return member;
paths = table[address.getHash('hex')];
assert(paths);
member.address = address;
member.paths = paths;
for (i = 0; i < paths.length; i++)
member.wallets.push(paths[i].id);
member.accounts = uniq(member.paths);
member.wallets = utils.uniq(member.wallets);
return member;
};
/**
* Map a transactions' addresses to wallet IDs.
* @param {TX} tx
@ -305,6 +133,8 @@ TXDB.prototype.getMap = function getMap(tx, callback) {
map = WalletMap.fromTX(table, tx);
utils.print(map.toJSON());
return callback(null, map);
});
};
@ -1814,6 +1644,280 @@ TXDB.prototype.zap = function zap(id, age, callback, force) {
});
};
/*
* Address->Wallet Mapping
*/
// Each address can potentially map to multiple
// accounts and wallets due to the fact that
// multisig accounts can have shared addresses.
// An address could map to 2 accounts on different
// wallets, or 2 accounts on the same wallet!
// In summary, bitcoin is hard. Use Bobchain instead.
//
// Table:
// [address-hash] -> [array of Path objects]
// '1edc6b6858fd12c64b26d8bd1e0e50d44b5bafb9':
// [Path {
// id: 'WLTZ3f5mMBsgWr1TcLzAdtLD8pkLcmWuBfPt',
// name: 'default',
// account: 0,
// change: 0,
// index: 0
// }]
//
// What we need:
// Table: Above.
// All: uniqified paths by id/name
// Outputs: Technically uniqified by ID, but id/name works too.
// What they need (api):
// outputs: [
// // Sum of value:
// { value: 0, id: wallet-id, name: account, index: account }
// ]
/**
* WalletMap
* @constructor
* @private
*/
function WalletMap(table) {
this.inputs = [];
this.outputs = [];
this.paths = [];
this.accounts = null;
this.wallets = [];
this.table = null;
}
WalletMap.prototype.fromTX = function fromTX(table, tx) {
var keys = Object.keys(table);
var i, input, output, hash, members, member;
var j, key, paths, path;
// Flatten paths and push all of
// them onto the `paths` array.
for (i = 0; i < keys.length; i++) {
key = keys[i];
paths = table[key];
for (j = 0; j < paths.length; j++) {
path = paths[j];
this.wallets.push(path.id);
this.paths.push(path);
}
}
this.wallets = utils.uniq(this.wallets);
this.accounts = uniq(this.paths);
this.table = table;
members = {};
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
hash = input.getHash('hex');
if (!hash)
continue;
member = members[hash];
if (!member) {
member = MapMember.fromMember(table, input);
members[hash] = member;
this.inputs.push(member);
continue;
}
if (input.coin)
member.value += input.coin.value;
}
members = {};
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
hash = output.getHash('hex');
member = members[hash];
if (!hash)
continue;
if (!member) {
member = MapMember.fromMember(table, output);
members[hash] = member;
this.outputs.push(member);
continue;
}
member.value += output.value;
}
return this;
};
WalletMap.fromTX = function fromTX(table, tx) {
return new WalletMap().fromTX(table, tx);
};
WalletMap.prototype.hasPaths = function hasPaths(address) {
var paths;
if (!address)
return false;
paths = this.table[address];
return paths && paths.length !== 0;
};
WalletMap.prototype.getPaths = function getPaths(address) {
return this.table[address];
};
WalletMap.prototype.toJSON = function toJSON() {
return {
inputs: this.inputs.map(function(input) {
return input.toJSON();
}),
outputs: this.outputs.map(function(output) {
return output.toJSON();
}),
paths: this.paths.map(function(path) {
return path.toJSON();
}),
accounts: this.accounts.map(function(path) {
return path.toAccount();
}),
wallets: this.wallets
};
};
WalletMap.prototype.fromJSON = function fromJSON(json) {
var table = {};
var i, account, path, input, output, hash;
for (i = 0; i < json.inputs.length; i++) {
input = json.inputs[i];
input = MapMember.fromJSON(input);
hash = input.getHash('hex');
table[hash] = input.paths;
this.inputs.push(input);
}
for (i = 0; i < json.outputs.length; i++) {
output = json.outputs[i];
output = MapMember.fromJSON(output);
hash = output.getHash('hex');
if (!table[hash])
table[hash] = output.paths;
this.outputs.push(output);
}
for (i = 0; i < json.paths.length; i++) {
path = json.paths[i];
this.paths.push(bcoin.path.fromJSON(path));
}
for (i = 0; i < json.accounts.length; i++) {
account = json.accounts[i];
this.accounts.push(bcoin.path.fromAccount(account));
}
this.wallets = json.wallets;
this.table = table;
return this;
};
WalletMap.fromJSON = function fromJSON(json) {
return new MapMember({}).fromJSON(json);
};
/**
* MapMember
* @constructor
* @private
*/
function MapMember() {
this.value = 0;
this.address = null;
this.paths = [];
this.accounts = [];
this.wallets = [];
}
MapMember.prototype.toJSON = function toJSON() {
return {
value: utils.btc(this.value),
address: this.address
? this.address.toBase58()
: null,
hash: this.address
? this.address.getHash('hex')
: null,
paths: this.paths.map(function(path) {
return path.toJSON();
}),
accounts: this.accounts.map(function(path) {
return path.toAccount();
}),
wallets: this.wallets
};
};
MapMember.prototype.fromJSON = function fromJSON(json) {
var i, account, path;
this.value = utils.satoshi(json.value);
this.address = bcoin.address.fromBase58(json.address);
for (i = 0; i < json.paths.length; i++) {
path = json.paths[i];
this.paths.push(bcoin.path.fromJSON(path));
}
for (i = 0; i < json.accounts.length; i++) {
account = json.accounts[i];
this.accounts.push(bcoin.path.fromAccount(account));
}
this.wallets = json.wallets;
return this;
};
MapMember.fromJSON = function fromJSON(json) {
return new MapMember().fromJSON(json);
};
MapMember.fromMember = function fromMember(table, io) {
var address = io.getAddress();
var member = new MapMember();
var i, paths;
if (io instanceof bcoin.input)
member.value = io.coin ? io.coin.value : 0;
else
member.value = io.value;
if (!address)
return member;
paths = table[address.getHash('hex')];
assert(paths);
member.address = address;
member.paths = paths;
for (i = 0; i < paths.length; i++)
member.wallets.push(paths[i].id);
member.accounts = uniq(member.paths);
member.wallets = utils.uniq(member.wallets);
return member;
};
/*
* Helpers
*/

View File

@ -1160,6 +1160,7 @@ WalletDB.prototype.getRedeem = function getRedeem(id, hash, callback) {
/**
* Path
* @constructor
* @private
*/
function Path() {
@ -1211,16 +1212,55 @@ Path.prototype.inspect = function() {
+ '>';
};
Path.prototype.toAccount = function toAccount() {
return {
id: this.id,
name: this.name,
account: this.account
};
};
Path.prototype.toJSON = function toJSON() {
return {
id: this.id,
name: this.name,
account: this.account,
change: this.change,
index: this.index
path: this.toPath()
};
};
Path.prototype.fromAccount = function fromAccount(json) {
this.id = json.id;
this.name = json.name;
this.account = json.account;
this.change = 0;
this.index = 0;
return this;
};
Path.fromAccount = function fromAccount(json) {
return new Path().fromAccount(json);
};
Path.prototype.fromJSON = function fromJSON(json) {
var indexes = bcoin.hd.parsePath(json.path, constants.hd.MAX_INDEX);
assert(indexes.length === 3);
assert(indexes[0] >= 0);
indexes[0] -= constants.hd.HARDENED;
this.id = json.id;
this.name = json.name;
this.account = indexes[0];
this.change = indexes[1];
this.index = indexes[2];
return this;
};
Path.fromJSON = function fromJSON(json) {
return new Path().fromJSON(json);
};
Path.prototype.toRaw = function toRaw(writer) {
var p = new BufferWriter(writer);
@ -1277,5 +1317,6 @@ function isAlpha(key) {
*/
exports = WalletDB;
exports.Path = Path;
module.exports = exports;