wallet: drop wallet map in favor of path info and tx details.
This commit is contained in:
parent
914bc8435d
commit
abd267b7d2
@ -2909,37 +2909,36 @@ RPC.prototype._toWalletTX = function _toWalletTX(tx, callback) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var receive, member, json;
|
var receive, member, json;
|
||||||
|
|
||||||
this.walletdb.tx.getMap(tx, function(err, map) {
|
this.walletdb.tx.toDetails(this.wallet.id, tx, function(err, details) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!map)
|
if (!details)
|
||||||
return callback(new RPCError('TX not found.'));
|
return callback(new RPCError('TX not found.'));
|
||||||
|
|
||||||
receive = map.inputs.length === 0;
|
receive = details.isReceive();
|
||||||
member = receive ? map.outputs[0] : map.inputs[0];
|
member = details.getMember();
|
||||||
assert(member);
|
|
||||||
|
|
||||||
json = {
|
json = {
|
||||||
amount: +utils.btc(tx.getOutputValue()),
|
amount: +utils.btc(details.getValue()),
|
||||||
confirmations: tx.getConfirmations(self.chain.height),
|
confirmations: details.confirmations,
|
||||||
blockhash: tx.block ? utils.revHex(tx.block) : null,
|
blockhash: details.block ? utils.revHex(details.block) : null,
|
||||||
blockindex: tx.index,
|
blockindex: details.index,
|
||||||
blocktime: tx.ts,
|
blocktime: details.ts,
|
||||||
txid: tx.rhash,
|
txid: utils.revHex(details.hash),
|
||||||
walletconflicts: [],
|
walletconflicts: [],
|
||||||
time: tx.ps,
|
time: details.ps,
|
||||||
timereceived: tx.ps,
|
timereceived: details.ps,
|
||||||
'bip125-replaceable': 'no',
|
'bip125-replaceable': 'no',
|
||||||
details: [{
|
details: [{
|
||||||
account: member.name,
|
account: member.path.name,
|
||||||
address: member.paths[0].address.toBase58(self.network),
|
address: member.address.toBase58(self.network),
|
||||||
category: receive ? 'receive' : 'send',
|
category: receive ? 'receive' : 'send',
|
||||||
amount: +utils.btc(member.value),
|
amount: +utils.btc(member.value),
|
||||||
label: member.name,
|
label: member.path.name,
|
||||||
vout: 0
|
vout: 0
|
||||||
}],
|
}],
|
||||||
hex: tx.toRaw().toString('hex')
|
hex: details.tx.toRaw().toString('hex')
|
||||||
};
|
};
|
||||||
|
|
||||||
callback(null, json);
|
callback(null, json);
|
||||||
@ -3199,32 +3198,31 @@ RPC.prototype._toListTX = function _toListTX(tx, callback) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var receive, member, json;
|
var receive, member, json;
|
||||||
|
|
||||||
this.walletdb.tx.getMap(tx, function(err, map) {
|
this.walletdb.tx.toDetails(this.wallet.id, tx, function(err, details) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!map)
|
if (!details)
|
||||||
return callback(new RPCError('TX not found.'));
|
return callback(new RPCError('TX not found.'));
|
||||||
|
|
||||||
receive = map.inputs.length === 0;
|
receive = details.isReceive();
|
||||||
member = receive ? map.outputs[0] : map.inputs[0];
|
member = details.getMember();
|
||||||
assert(member);
|
|
||||||
|
|
||||||
json = {
|
json = {
|
||||||
account: member.name,
|
account: member.path.name,
|
||||||
address: member.paths[0].address.toBase58(self.network),
|
address: member.address.toBase58(self.network),
|
||||||
category: receive ? 'receive' : 'send',
|
category: receive ? 'receive' : 'send',
|
||||||
amount: +utils.btc(member.value),
|
amount: +utils.btc(member.value),
|
||||||
label: member.name,
|
label: member.path.name,
|
||||||
vout: 0,
|
vout: 0,
|
||||||
confirmations: tx.getConfirmations(self.chain.height),
|
confirmations: details.confirmations,
|
||||||
blockhash: tx.block ? utils.revHex(tx.block) : null,
|
blockhash: details.block ? utils.revHex(details.block) : null,
|
||||||
blockindex: tx.index,
|
blockindex: details.index,
|
||||||
blocktime: tx.ts,
|
blocktime: details.ts,
|
||||||
txid: tx.rhash,
|
txid: utils.revHex(details.hash),
|
||||||
walletconflicts: [],
|
walletconflicts: [],
|
||||||
time: tx.ps,
|
time: details.ps,
|
||||||
timereceived: tx.ps,
|
timereceived: details.ps,
|
||||||
'bip125-replaceable': 'no'
|
'bip125-replaceable': 'no'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -968,49 +968,36 @@ HTTPServer.prototype._initIO = function _initIO() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('tx', function(tx, map) {
|
this.walletdb.on('tx', function(id, tx, details) {
|
||||||
var summary = map.toJSON();
|
details = details.toJSON();
|
||||||
tx = tx.toJSON();
|
self.server.io.to(id).emit('wallet tx', details);
|
||||||
map.getWallets().forEach(function(id) {
|
self.server.io.to('!all').emit('wallet tx', id, details);
|
||||||
self.server.io.to(id).emit('wallet tx', tx, summary);
|
|
||||||
});
|
|
||||||
self.server.io.to('!all').emit('wallet tx', tx, summary);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('confirmed', function(tx, map) {
|
this.walletdb.on('confirmed', function(id, tx, details) {
|
||||||
var summary = map.toJSON();
|
details = details.toJSON();
|
||||||
tx = tx.toJSON();
|
self.server.io.to(id).emit('wallet confirmed', details);
|
||||||
map.getWallets().forEach(function(id) {
|
self.server.io.to('!all').emit('wallet confirmed', id, details);
|
||||||
self.server.io.to(id).emit('wallet confirmed', tx, summary);
|
|
||||||
});
|
|
||||||
self.server.io.to('!all').emit('wallet confirmed', tx, summary);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('updated', function(tx, map) {
|
this.walletdb.on('updated', function(id, tx, details) {
|
||||||
var summary = map.toJSON();
|
details = details.toJSON();
|
||||||
tx = tx.toJSON();
|
self.server.io.to(id).emit('wallet updated', details);
|
||||||
map.getWallets().forEach(function(id) {
|
self.server.io.to('!all').emit('wallet updated', id, details);
|
||||||
self.server.io.to(id).emit('wallet updated', tx, summary);
|
|
||||||
});
|
|
||||||
self.server.io.to('!all').emit('wallet updated', tx, summary);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('balances', function(balances) {
|
this.walletdb.on('balance', function(id, balance, details) {
|
||||||
var json = {};
|
balance = {
|
||||||
Object.keys(balances).forEach(function(id) {
|
confirmed: utils.btc(balance.confirmed),
|
||||||
json[id] = {
|
unconfirmed: utils.btc(balance.unconfirmed),
|
||||||
confirmed: utils.btc(balances[id].confirmed),
|
total: utils.btc(balance.total)
|
||||||
unconfirmed: utils.btc(balances[id].unconfirmed),
|
};
|
||||||
total: utils.btc(balances[id].total)
|
self.server.io.to(id).emit('wallet balance', balance);
|
||||||
};
|
self.server.io.to('!all').emit('wallet balance', id, balance);
|
||||||
self.server.io.to(id).emit('wallet balance', json[id], id);
|
|
||||||
self.server.io.to('!all').emit('wallet balance', json[id], id);
|
|
||||||
});
|
|
||||||
self.server.io.to('!all').emit('wallet balances', json);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.walletdb.on('address', function(receive, change, map) {
|
this.walletdb.on('address', function(id, receive, change, details) {
|
||||||
var summary = map.toJSON();
|
details = details.toJSON();
|
||||||
|
|
||||||
receive = receive.map(function(address) {
|
receive = receive.map(function(address) {
|
||||||
return address.toJSON();
|
return address.toJSON();
|
||||||
@ -1020,11 +1007,8 @@ HTTPServer.prototype._initIO = function _initIO() {
|
|||||||
return address.toJSON();
|
return address.toJSON();
|
||||||
});
|
});
|
||||||
|
|
||||||
map.getWallets().forEach(function(id) {
|
self.server.io.to(id).emit('wallet address', receive, change, details);
|
||||||
self.server.io.to(id).emit('wallet address', receive, change, summary);
|
self.server.io.to('!all').emit('wallet address', id, receive, change, details);
|
||||||
});
|
|
||||||
|
|
||||||
self.server.io.to('!all').emit('wallet address', receive, change, summary);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1030,18 +1030,19 @@ Wallet.prototype.getOutputPaths = function getOutputPaths(tx, callback) {
|
|||||||
* Sync address depths based on a transaction's outputs.
|
* Sync address depths based on a transaction's outputs.
|
||||||
* This is used for deriving new addresses when
|
* This is used for deriving new addresses when
|
||||||
* a confirmed transaction is seen.
|
* a confirmed transaction is seen.
|
||||||
* @param {WalletMap} map
|
* @param {WalletMap} info
|
||||||
* @param {Function} callback - Returns [Errr, Boolean]
|
* @param {Function} callback - Returns [Errr, Boolean]
|
||||||
* (true if new addresses were allocated).
|
* (true if new addresses were allocated).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Wallet.prototype.syncOutputDepth = function syncOutputDepth(map, callback) {
|
Wallet.prototype.syncOutputDepth = function syncOutputDepth(info, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var change = [];
|
var change = [];
|
||||||
var receive = [];
|
var receive = [];
|
||||||
|
var accounts = {};
|
||||||
var i, path, unlock;
|
var i, path, unlock;
|
||||||
|
|
||||||
unlock = this.writeLock.lock(syncOutputDepth, [map, callback]);
|
unlock = this.writeLock.lock(syncOutputDepth, [info, callback]);
|
||||||
|
|
||||||
if (!unlock)
|
if (!unlock)
|
||||||
return;
|
return;
|
||||||
@ -1050,8 +1051,22 @@ Wallet.prototype.syncOutputDepth = function syncOutputDepth(map, callback) {
|
|||||||
|
|
||||||
this.start();
|
this.start();
|
||||||
|
|
||||||
utils.forEachSerial(map.outputs, function(output, next) {
|
for (i = 0; i < info.paths.length; i++) {
|
||||||
var paths = output.paths;
|
path = info.paths[i];
|
||||||
|
|
||||||
|
if (path.id !== this.id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!accounts[path.account])
|
||||||
|
accounts[path.account] = [];
|
||||||
|
|
||||||
|
accounts[path.account].push(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
accounts = utils.values(accounts);
|
||||||
|
|
||||||
|
utils.forEachSerial(accounts, function(paths, next) {
|
||||||
|
var account = paths[0].account;
|
||||||
var receiveDepth = -1;
|
var receiveDepth = -1;
|
||||||
var changeDepth = -1;
|
var changeDepth = -1;
|
||||||
|
|
||||||
@ -1070,7 +1085,7 @@ Wallet.prototype.syncOutputDepth = function syncOutputDepth(map, callback) {
|
|||||||
receiveDepth += 2;
|
receiveDepth += 2;
|
||||||
changeDepth += 2;
|
changeDepth += 2;
|
||||||
|
|
||||||
self.getAccount(output.account, function(err, account) {
|
self.getAccount(account, function(err, account) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
|
|||||||
@ -101,35 +101,35 @@ WalletDB.prototype._init = function _init() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEvent(event, tx, map) {
|
function handleEvent(event, tx, info) {
|
||||||
var i, path;
|
var i, id, details;
|
||||||
|
|
||||||
self.emit(event, tx, map);
|
for (i = 0; i < info.wallets.length; i++) {
|
||||||
|
id = info.wallets[i];
|
||||||
for (i = 0; i < map.accounts.length; i++) {
|
details = info.toDetails(id);
|
||||||
path = map.accounts[i];
|
self.emit(event, id, tx, details);
|
||||||
self.fire(path.id, event, tx, path.name);
|
self.fire(id, event, tx, details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tx.on('tx', function(tx, map) {
|
this.tx.on('tx', function(tx, info) {
|
||||||
handleEvent('tx', tx, map);
|
handleEvent('tx', tx, info);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.tx.on('conflict', function(tx, map) {
|
this.tx.on('conflict', function(tx, info) {
|
||||||
handleEvent('conflict', tx, map);
|
handleEvent('conflict', tx, info);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.tx.on('confirmed', function(tx, map) {
|
this.tx.on('confirmed', function(tx, info) {
|
||||||
handleEvent('confirmed', tx, map);
|
handleEvent('confirmed', tx, info);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.tx.on('unconfirmed', function(tx, map) {
|
this.tx.on('unconfirmed', function(tx, info) {
|
||||||
handleEvent('unconfirmed', tx, map);
|
handleEvent('unconfirmed', tx, info);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.tx.on('updated', function(tx, map) {
|
this.tx.on('updated', function(tx, info) {
|
||||||
handleEvent('updated', tx, map);
|
handleEvent('updated', tx, info);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -248,16 +248,15 @@ WalletDB.prototype.commit = function commit(id, callback) {
|
|||||||
* Emit balance events after a tx is saved.
|
* Emit balance events after a tx is saved.
|
||||||
* @private
|
* @private
|
||||||
* @param {TX} tx
|
* @param {TX} tx
|
||||||
* @param {WalletMap} map
|
* @param {WalletMap} info
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.updateBalances = function updateBalances(tx, map, callback) {
|
WalletDB.prototype.updateBalances = function updateBalances(tx, info, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var balances = {};
|
var details;
|
||||||
var i, id, keys;
|
|
||||||
|
|
||||||
utils.forEachSerial(map.getOutputWallets(), function(id, next) {
|
utils.forEachSerial(info.wallets, function(id, next) {
|
||||||
if (self.listeners('balances').length === 0
|
if (self.listeners('balances').length === 0
|
||||||
&& !self.hasListener(id, 'balance')) {
|
&& !self.hasListener(id, 'balance')) {
|
||||||
return next();
|
return next();
|
||||||
@ -267,44 +266,34 @@ WalletDB.prototype.updateBalances = function updateBalances(tx, map, callback) {
|
|||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
balances[id] = balance;
|
details = info.toDetails(id);
|
||||||
|
self.emit('balance', id, balance, details);
|
||||||
|
self.fire(id, 'balance', balance, details);
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
}, function(err) {
|
}, callback);
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
keys = Object.keys(balances);
|
|
||||||
|
|
||||||
for (i = 0; i < keys.length; i++) {
|
|
||||||
id = keys[i];
|
|
||||||
self.fire(id, 'balance', balances[id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.emit('balances', balances, map);
|
|
||||||
|
|
||||||
return callback(null, balances);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derive new addresses after a tx is saved.
|
* Derive new addresses after a tx is saved.
|
||||||
* @private
|
* @private
|
||||||
* @param {TX} tx
|
* @param {TX} tx
|
||||||
* @param {WalletMap} map
|
* @param {WalletMap} info
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.syncOutputs = function syncOutputs(tx, map, callback) {
|
WalletDB.prototype.syncOutputs = function syncOutputs(tx, info, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var details;
|
||||||
|
|
||||||
utils.forEachSerial(map.getOutputWallets(), function(id, next) {
|
utils.forEachSerial(info.wallets, function(id, next) {
|
||||||
self.syncOutputDepth(id, map, function(err, receive, change) {
|
self.syncOutputDepth(id, info, function(err, receive, change) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
self.fire(id, 'address', receive, change);
|
details = info.toDetails(id);
|
||||||
self.emit('address', receive, change, map);
|
self.emit('address', id, receive, change, details);
|
||||||
|
self.fire(id, 'address', receive, change, details);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
}, callback);
|
}, callback);
|
||||||
@ -314,17 +303,17 @@ WalletDB.prototype.syncOutputs = function syncOutputs(tx, map, callback) {
|
|||||||
* Derive new addresses and emit balance.
|
* Derive new addresses and emit balance.
|
||||||
* @private
|
* @private
|
||||||
* @param {TX} tx
|
* @param {TX} tx
|
||||||
* @param {WalletMap} map
|
* @param {WalletMap} info
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.handleTX = function handleTX(tx, map, callback) {
|
WalletDB.prototype.handleTX = function handleTX(tx, info, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.syncOutputs(tx, map, function(err) {
|
this.syncOutputs(tx, info, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
self.updateBalances(tx, map, callback);
|
self.updateBalances(tx, info, callback);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1366,9 +1355,9 @@ WalletDB.prototype.fetchWallet = function fetchWallet(id, callback, handler) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletDB.prototype.syncOutputDepth = function syncOutputDepth(id, map, callback) {
|
WalletDB.prototype.syncOutputDepth = function syncOutputDepth(id, info, callback) {
|
||||||
this.fetchWallet(id, callback, function(wallet, callback) {
|
this.fetchWallet(id, callback, function(wallet, callback) {
|
||||||
wallet.syncOutputDepth(map, callback);
|
wallet.syncOutputDepth(info, callback);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1591,6 +1580,7 @@ Path.prototype.toJSON = function toJSON() {
|
|||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
change: this.change === 1,
|
||||||
path: this.toPath()
|
path: this.toPath()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -1636,48 +1626,6 @@ Path.prototype.toKey = function toKey() {
|
|||||||
return this.id + '/' + this.account;
|
return this.id + '/' + this.account;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert path to a compact json object.
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.toCompact = function toCompact() {
|
|
||||||
return {
|
|
||||||
path: 'm/' + this.change + '/' + this.index,
|
|
||||||
address: this.address ? this.address.toBase58() : null
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject properties from compact json object.
|
|
||||||
* @private
|
|
||||||
* @param {Object} json
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.prototype.fromCompact = function fromCompact(json) {
|
|
||||||
var indexes = bcoin.hd.parsePath(json.path, constants.hd.MAX_INDEX);
|
|
||||||
|
|
||||||
assert(indexes.length === 2);
|
|
||||||
|
|
||||||
this.change = indexes[0];
|
|
||||||
this.index = indexes[1];
|
|
||||||
this.address = json.address
|
|
||||||
? bcoin.address.fromBase58(json.address)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate path from compact json object.
|
|
||||||
* @param {Object} json
|
|
||||||
* @returns {Path}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path.fromCompact = function fromCompact(json) {
|
|
||||||
return new Path().fromCompact(json);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspect the path.
|
* Inspect the path.
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user