wallet work.
This commit is contained in:
parent
b8997c9212
commit
ae7bbeb065
@ -181,6 +181,7 @@ function Environment(options) {
|
|||||||
this.wallet = require('./wallet');
|
this.wallet = require('./wallet');
|
||||||
this.account = this.wallet.Account;
|
this.account = this.wallet.Account;
|
||||||
this.walletdb = require('./walletdb');
|
this.walletdb = require('./walletdb');
|
||||||
|
this.path = this.walletdb.Path;
|
||||||
this.provider = this.walletdb.Provider;
|
this.provider = this.walletdb.Provider;
|
||||||
this.peer = require('./peer');
|
this.peer = require('./peer');
|
||||||
this.pool = require('./pool');
|
this.pool = require('./pool');
|
||||||
|
|||||||
@ -110,178 +110,6 @@ TXDB.prototype._testFilter = function _testFilter(addresses) {
|
|||||||
return false;
|
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.
|
* Map a transactions' addresses to wallet IDs.
|
||||||
* @param {TX} tx
|
* @param {TX} tx
|
||||||
@ -305,6 +133,8 @@ TXDB.prototype.getMap = function getMap(tx, callback) {
|
|||||||
|
|
||||||
map = WalletMap.fromTX(table, tx);
|
map = WalletMap.fromTX(table, tx);
|
||||||
|
|
||||||
|
utils.print(map.toJSON());
|
||||||
|
|
||||||
return callback(null, map);
|
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
|
* Helpers
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1160,6 +1160,7 @@ WalletDB.prototype.getRedeem = function getRedeem(id, hash, callback) {
|
|||||||
/**
|
/**
|
||||||
* Path
|
* Path
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Path() {
|
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() {
|
Path.prototype.toJSON = function toJSON() {
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
account: this.account,
|
path: this.toPath()
|
||||||
change: this.change,
|
|
||||||
index: this.index
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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) {
|
Path.prototype.toRaw = function toRaw(writer) {
|
||||||
var p = new BufferWriter(writer);
|
var p = new BufferWriter(writer);
|
||||||
|
|
||||||
@ -1277,5 +1317,6 @@ function isAlpha(key) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
exports = WalletDB;
|
exports = WalletDB;
|
||||||
|
exports.Path = Path;
|
||||||
|
|
||||||
module.exports = exports;
|
module.exports = exports;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user