wallet work.
This commit is contained in:
parent
b8997c9212
commit
ae7bbeb065
@ -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');
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user