txdb: less confusing tx details.

This commit is contained in:
Christopher Jeffrey 2016-10-18 14:27:56 -07:00
parent 9ed439b60c
commit 11b2f1a7bc
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 336 additions and 188 deletions

View File

@ -1259,32 +1259,27 @@ HTTPServer.prototype._initIO = function _initIO() {
});
});
this.walletdb.on('tx', function(id, tx, info) {
var details = info.toJSON();
this.walletdb.on('tx', function(id, tx, details) {
self.server.io.to(id).emit('wallet tx', details);
self.server.io.to('!all').emit('wallet tx', id, details);
});
this.walletdb.on('confirmed', function(id, tx, info) {
var details = info.toJSON();
this.walletdb.on('confirmed', function(id, tx, details) {
self.server.io.to(id).emit('wallet confirmed', details);
self.server.io.to('!all').emit('wallet confirmed', id, details);
});
this.walletdb.on('unconfirmed', function(id, tx, info) {
var details = info.toJSON();
this.walletdb.on('unconfirmed', function(id, tx, details) {
self.server.io.to(id).emit('wallet unconfirmed', details);
self.server.io.to('!all').emit('wallet unconfirmed', id, details);
});
this.walletdb.on('conflict', function(id, tx, info) {
var details = info.toJSON();
this.walletdb.on('conflict', function(id, tx, details) {
self.server.io.to(id).emit('wallet conflict', details);
self.server.io.to('!all').emit('wallet conflict', id, details);
});
this.walletdb.on('balance', function(id, balance) {
var json = balance.toJSON();
self.server.io.to(id).emit('wallet balance', json);
self.server.io.to('!all').emit('wallet balance', id, json);
});

View File

@ -331,11 +331,11 @@ TXDB.prototype.commit = co(function* commit() {
* @private
* @param {String} event
* @param {Object} data
* @param {PathInfo} info
* @param {PathInfo} details
*/
TXDB.prototype.emit = function emit(event, data, info) {
this.events.push([event, data, info]);
TXDB.prototype.emit = function emit(event, data, details) {
this.events.push([event, data, details]);
};
/**
@ -436,8 +436,22 @@ TXDB.prototype.values = function values(options) {
* @returns {Promise} - Returns {@link PathInfo}.
*/
TXDB.prototype.getPathInfo = function getPathInfo(tx) {
return this.wallet.getPathInfo(tx);
TXDB.prototype.getPath = function getPath(output) {
if (!output)
return Promise.resolve();
return this.wallet.getPath(output.getAddress());
};
/**
* Map a transactions' addresses to wallet IDs.
* @param {TX} tx
* @returns {Promise} - Returns {@link PathInfo}.
*/
TXDB.prototype.hasPath = function hasPath(output) {
if (!output)
return Promise.resolve();
return this.wallet.hasPath(output.getAddress());
};
/**
@ -478,7 +492,7 @@ TXDB.prototype.verifyInputs = co(function* verifyInputs(tx) {
var hasOrphans = false;
var orphans = [];
var i, input, prevout;
var path, key, coin, spent;
var key, coin, spent;
if (tx.isCoinbase())
return true;
@ -519,12 +533,8 @@ TXDB.prototype.verifyInputs = co(function* verifyInputs(tx) {
continue;
}
path = yield this.wallet.hasPath(input.getAddress());
if (!path)
continue;
orphans[i] = true;
if (yield this.hasPath(input))
orphans[i] = true;
}
for (i = 0; i < tx.inputs.length; i++) {
@ -627,11 +637,10 @@ TXDB.prototype.resolveOutputs = co(function* resolveOutputs(tx, resolved) {
* double spenders, and verify inputs.
* @private
* @param {TX} tx
* @param {PathInfo} info
* @returns {Promise}
*/
TXDB.prototype.removeConflicts = co(function* removeConflicts(tx, info) {
TXDB.prototype.removeConflicts = co(function* removeConflicts(tx) {
var hash = tx.hash('hex');
var i, input, prevout, spent;
@ -660,18 +669,16 @@ TXDB.prototype.removeConflicts = co(function* removeConflicts(tx, info) {
/**
* Add transaction, runs `confirm()` and `verify()`.
* @param {TX} tx
* @param {PathInfo} info
* @returns {Promise}
*/
TXDB.prototype.add = co(function* add(tx) {
var info = yield this.getPathInfo(tx);
var result;
this.start();
try {
result = yield this._add(tx, info);
result = yield this._add(tx);
} catch (e) {
this.drop();
throw e;
@ -686,43 +693,53 @@ TXDB.prototype.add = co(function* add(tx) {
* Add transaction without a lock.
* @private
* @param {TX} tx
* @param {PathInfo} info
* @returns {Promise}
*/
TXDB.prototype._add = co(function* add(tx, info) {
TXDB.prototype._add = co(function* add(tx) {
var hash = tx.hash('hex');
var path, account;
var i, result, input, output, coin;
var prevout, key, spender, raw;
var path, account, existing;
var i, input, output, coin;
var prevout, key, spender, raw, details;
assert(!tx.mutable, 'Cannot add mutable TX to wallet.');
existing = yield this.getTX(hash);
if (existing) {
// Existing tx is already confirmed. Ignore.
if (existing.height !== -1)
return;
// The incoming tx won't confirm the
// existing one anyway. Ignore.
if (tx.height === -1)
return;
// Attempt to confirm tx before adding it.
return yield this.confirm(tx, existing);
}
if (tx.height === -1) {
// We ignore double spends from the mempool.
if (yield this.isDoubleSpend(tx))
return false;
return;
// We ignore any unconfirmed txs
// that are replace-by-fee.
if (yield this.isRBF(tx)) {
this.put(layout.r(hash), DUMMY);
return false;
return;
}
} else {
// This potentially removes double-spenders.
yield this.removeConflicts(tx, info);
yield this.removeConflicts(tx);
// Delete the replace-by-fee record.
this.del(layout.r(hash));
}
// Attempt to confirm tx before adding it.
result = yield this.confirm(tx, info);
// Ignore if we already have this tx.
if (result)
return true;
details = new Details(this, tx);
this.put(layout.t(hash), tx.toExtended());
@ -733,19 +750,6 @@ TXDB.prototype._add = co(function* add(tx, info) {
this.put(layout.m(tx.ps, hash), DUMMY);
for (i = 0; i < info.accounts.length; i++) {
account = info.accounts[i];
this.put(layout.T(account, hash), DUMMY);
if (tx.height === -1)
this.put(layout.P(account, hash), DUMMY);
else
this.put(layout.H(account, tx.height, hash), DUMMY);
this.put(layout.M(account, tx.ps, hash), DUMMY);
}
// Consume unspent money or add orphans
if (!tx.isCoinbase()) {
for (i = 0; i < tx.inputs.length; i++) {
@ -757,9 +761,11 @@ TXDB.prototype._add = co(function* add(tx, info) {
if (!coin)
continue;
path = info.getPath(coin);
path = yield this.getPath(coin);
assert(path);
details.addInput(i, path, coin);
key = prevout.hash + prevout.index;
spender = Outpoint.fromTX(tx, i).toRaw();
@ -786,7 +792,7 @@ TXDB.prototype._add = co(function* add(tx, info) {
// Add unspent outputs or resolve orphans.
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
path = info.getPath(output);
path = yield this.getPath(output);
key = hash + i;
// Do not add unspents for
@ -794,6 +800,8 @@ TXDB.prototype._add = co(function* add(tx, info) {
if (!path)
continue;
details.addOutput(i, path);
coin = Coin.fromTX(tx, i);
raw = coin.toRaw();
@ -809,20 +817,33 @@ TXDB.prototype._add = co(function* add(tx, info) {
this.coinCache.set(key, raw);
}
for (i = 0; i < details.accounts.length; i++) {
account = details.accounts[i];
this.put(layout.T(account, hash), DUMMY);
if (tx.height === -1)
this.put(layout.P(account, hash), DUMMY);
else
this.put(layout.H(account, tx.height, hash), DUMMY);
this.put(layout.M(account, tx.ps, hash), DUMMY);
}
this.pending.tx++;
this.put(layout.R, this.pending.commit());
// Clear any locked coins to free up memory.
this.unlockTX(tx);
this.emit('tx', tx, info);
this.emit('tx', tx, details);
if (tx.height !== -1)
this.emit('confirmed', tx, info);
this.emit('confirmed', tx, details);
this.emit('balance', this.pending.toBalance(), info);
this.emit('balance', this.pending.toBalance(), details);
return true;
return details;
});
/**
@ -839,7 +860,7 @@ TXDB.prototype._add = co(function* add(tx, info) {
TXDB.prototype.removeConflict = co(function* removeConflict(hash, ref) {
var tx = yield this.getTX(hash);
var info;
var details;
assert(tx);
@ -847,14 +868,16 @@ TXDB.prototype.removeConflict = co(function* removeConflict(hash, ref) {
this.drop();
info = yield this.removeRecursive(tx);
details = yield this.removeRecursive(tx);
this.start();
this.logger.warning('Removed conflict: %s.', tx.rhash);
// Emit the _removed_ transaction.
this.emit('conflict', tx, info);
this.emit('conflict', tx, details);
return details;
});
/**
@ -867,7 +890,7 @@ TXDB.prototype.removeConflict = co(function* removeConflict(hash, ref) {
TXDB.prototype.removeRecursive = co(function* removeRecursive(tx) {
var hash = tx.hash('hex');
var i, spent, stx, info;
var i, spent, stx, details;
for (i = 0; i < tx.outputs.length; i++) {
spent = yield this.getSpent(hash, i);
@ -886,13 +909,13 @@ TXDB.prototype.removeRecursive = co(function* removeRecursive(tx) {
this.start();
// Remove the spender.
info = yield this.lazyRemove(tx);
details = yield this.lazyRemove(tx);
assert(info);
assert(details);
yield this.commit();
return info;
return details;
});
/**
@ -1012,32 +1035,16 @@ TXDB.prototype.isSpending = co(function* isSpending(hash, index) {
* Attempt to confirm a transaction.
* @private
* @param {TX} tx
* @param {AddressMap} info
* @returns {Promise} - Returns Boolean. `false` if
* the transaction should be added to the database, `true` if the
* transaction was confirmed, or should be ignored.
*/
TXDB.prototype.confirm = co(function* confirm(tx, info) {
TXDB.prototype.confirm = co(function* confirm(tx, existing) {
var hash = tx.hash('hex');
var i, account, existing, output, coin;
var i, account, output, coin;
var input, prevout, path, spender, coins;
var key, raw;
existing = yield this.getTX(hash);
// Haven't seen this tx before, add it.
if (!existing)
return false;
// Existing tx is already confirmed. Ignore.
if (existing.height !== -1)
return true;
// The incoming tx won't confirm the
// existing one anyway. Ignore.
if (tx.height === -1)
return true;
var key, raw, details;
// Inject block properties.
existing.ts = tx.ts;
@ -1046,17 +1053,13 @@ TXDB.prototype.confirm = co(function* confirm(tx, info) {
existing.block = tx.block;
tx = existing;
details = new Details(this, tx);
this.put(layout.t(hash), tx.toExtended());
this.del(layout.p(hash));
this.put(layout.h(tx.height, hash), DUMMY);
for (i = 0; i < info.accounts.length; i++) {
account = info.accounts[i];
this.del(layout.P(account, hash));
this.put(layout.H(account, tx.height, hash), DUMMY);
}
// Consume unspent money or add orphans
if (!tx.isCoinbase()) {
coins = yield this.fillHistory(tx);
@ -1082,10 +1085,14 @@ TXDB.prototype.confirm = co(function* confirm(tx, info) {
assert(coin.height !== -1);
input.coin = coin;
// Only bother if this input is ours.
path = info.getPath(coin);
path = yield this.getPath(coin);
assert(path);
details.addInput(i, path, coin);
key = prevout.hash + prevout.index;
this.del(layout.S(prevout.hash, prevout.index));
@ -1102,12 +1109,15 @@ TXDB.prototype.confirm = co(function* confirm(tx, info) {
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
path = yield this.getPath(output);
key = hash + i;
// Only update coins if this output is ours.
if (!info.hasPath(output))
if (!path)
continue;
details.addOutput(i, path);
// Update spent coin.
yield this.updateSpentCoin(tx, i);
@ -1127,16 +1137,22 @@ TXDB.prototype.confirm = co(function* confirm(tx, info) {
this.coinCache.set(key, raw);
}
for (i = 0; i < details.accounts.length; i++) {
account = details.accounts[i];
this.del(layout.P(account, hash));
this.put(layout.H(account, tx.height, hash), DUMMY);
}
this.put(layout.R, this.pending.commit());
// Clear any locked coins to free up memory.
this.unlockTX(tx);
this.emit('tx', tx, info);
this.emit('confirmed', tx, info);
this.emit('balance', this.pending.toBalance(), info);
this.emit('tx', tx, details);
this.emit('confirmed', tx, details);
this.emit('balance', this.pending.toBalance(), details);
return true;
return details;
});
/**
@ -1146,12 +1162,12 @@ TXDB.prototype.confirm = co(function* confirm(tx, info) {
*/
TXDB.prototype.remove = co(function* remove(hash) {
var result;
var details;
this.start();
try {
result = yield this._remove(hash);
details = yield this._remove(hash);
} catch (e) {
this.drop();
throw e;
@ -1159,7 +1175,7 @@ TXDB.prototype.remove = co(function* remove(hash) {
yield this.commit();
return result;
return details;
});
/**
@ -1171,21 +1187,21 @@ TXDB.prototype.remove = co(function* remove(hash) {
TXDB.prototype._remove = co(function* remove(hash) {
var tx = yield this.getTX(hash);
var info;
var details;
if (!tx)
return;
this.drop();
info = yield this.removeRecursive(tx);
details = yield this.removeRecursive(tx);
this.start();
if (!info)
if (!details)
return;
return info;
return details;
});
/**
@ -1197,25 +1213,22 @@ TXDB.prototype._remove = co(function* remove(hash) {
*/
TXDB.prototype.lazyRemove = co(function* lazyRemove(tx) {
var info = yield this.getPathInfo(tx);
if (!info)
return;
return yield this.__remove(tx, info);
return yield this.__remove(tx);
});
/**
* Remove a transaction from the database. Disconnect inputs.
* @private
* @param {TX} tx
* @param {AddressMap} info
* @returns {Promise}
*/
TXDB.prototype.__remove = co(function* remove(tx, info) {
TXDB.prototype.__remove = co(function* remove(tx) {
var hash = tx.hash('hex');
var i, path, account, key, prevout;
var input, output, coin, coins, raw;
var input, output, coin, coins, raw, details;
details = new Details(this, tx);
this.del(layout.t(hash));
@ -1226,19 +1239,6 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
this.del(layout.m(tx.ps, hash));
for (i = 0; i < info.accounts.length; i++) {
account = info.accounts[i];
this.del(layout.T(account, hash));
if (tx.height === -1)
this.del(layout.P(account, hash));
else
this.del(layout.H(account, tx.height, hash));
this.del(layout.M(account, tx.ps, hash));
}
if (!tx.isCoinbase()) {
coins = yield this.fillHistory(tx);
@ -1251,9 +1251,11 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
if (!coin)
continue;
path = info.getPath(coin);
path = yield this.getPath(coin);
assert(path);
details.addInput(i, path, coin);
this.pending.unconfirmed += coin.value;
this.del(layout.s(prevout.hash, prevout.index));
@ -1277,11 +1279,13 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
key = hash + i;
path = info.getPath(output);
path = yield this.getPath(output);
if (!path)
continue;
details.addOutput(i, path);
this.pending.coin--;
this.pending.unconfirmed -= output.value;
@ -1294,13 +1298,26 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
this.coinCache.remove(key);
}
for (i = 0; i < details.accounts.length; i++) {
account = details.accounts[i];
this.del(layout.T(account, hash));
if (tx.height === -1)
this.del(layout.P(account, hash));
else
this.del(layout.H(account, tx.height, hash));
this.del(layout.M(account, tx.ps, hash));
}
this.pending.tx--;
this.put(layout.R, this.pending.commit());
this.emit('remove tx', tx, info);
this.emit('balance', this.pending.toBalance(), info);
this.emit('remove tx', tx, details);
this.emit('balance', this.pending.toBalance(), details);
return info;
return details;
});
/**
@ -1310,12 +1327,12 @@ TXDB.prototype.__remove = co(function* remove(tx, info) {
*/
TXDB.prototype.unconfirm = co(function* unconfirm(hash) {
var result;
var details;
this.start();
try {
result = yield this._unconfirm(hash);
details = yield this._unconfirm(hash);
} catch (e) {
this.drop();
throw e;
@ -1323,7 +1340,7 @@ TXDB.prototype.unconfirm = co(function* unconfirm(hash) {
yield this.commit();
return result;
return details;
});
/**
@ -1335,29 +1352,23 @@ TXDB.prototype.unconfirm = co(function* unconfirm(hash) {
TXDB.prototype._unconfirm = co(function* unconfirm(hash) {
var tx = yield this.getTX(hash);
var info, result;
var details;
if (!tx)
return false;
info = yield this.getPathInfo(tx);
details = yield this.__unconfirm(tx);
if (!info)
return false;
result = yield this.__unconfirm(tx, info);
return result;
return details;
});
/**
* Unconfirm a transaction. This is usually necessary after a reorg.
* @param {Hash} hash
* @param {AddressMap} info
* @returns {Promise}
*/
TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
TXDB.prototype.__unconfirm = co(function* unconfirm(tx) {
var hash = tx.hash('hex');
var height = tx.height;
var i, account, output, key, coin, coins;
@ -1368,17 +1379,13 @@ TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
tx.unsetBlock();
details = new Details(this, tx);
this.put(layout.t(hash), tx.toExtended());
this.put(layout.p(hash), DUMMY);
this.del(layout.h(height, hash));
for (i = 0; i < info.accounts.length; i++) {
account = info.accounts[i];
this.put(layout.P(account, hash), DUMMY);
this.del(layout.H(account, height, hash));
}
// Consume unspent money or add orphans
if (!tx.isCoinbase()) {
coins = yield this.fillHistory(tx);
@ -1396,9 +1403,11 @@ TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
raw = coin.toRaw();
path = info.getPath(coin);
path = yield this.getPath(coin);
assert(path);
details.addInput(i, path, coin);
key = prevout.hash + prevout.index;
spender = Outpoint.fromTX(tx, i).toRaw();
@ -1417,6 +1426,7 @@ TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
path = yield this.getPath(output);
key = hash + i;
// Update spent coin.
@ -1427,6 +1437,8 @@ TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
if (!coin)
continue;
details.addOutput(i, path);
coin.height = -1;
raw = coin.toRaw();
@ -1438,12 +1450,18 @@ TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
this.coinCache.set(key, raw);
}
for (i = 0; i < details.accounts.length; i++) {
account = details.accounts[i];
this.put(layout.P(account, hash), DUMMY);
this.del(layout.H(account, height, hash));
}
this.put(layout.R, this.pending.commit());
this.emit('unconfirmed', tx, info);
this.emit('balance', this.pending.toBalance(), info);
this.emit('unconfirmed', tx, details);
this.emit('balance', this.pending.toBalance(), details);
return info;
return details;
});
/**
@ -2105,7 +2123,8 @@ TXDB.prototype.getDetails = co(function* getDetails(hash) {
*/
TXDB.prototype.toDetails = co(function* toDetails(tx) {
var i, out, txs, details, info;
var i, out, txs, details;
var coins, coin, path, input, output;
if (Array.isArray(tx)) {
out = [];
@ -2124,14 +2143,23 @@ TXDB.prototype.toDetails = co(function* toDetails(tx) {
return out;
}
yield this.fillHistory(tx);
details = new Details(this, tx);
info = yield this.getPathInfo(tx);
coins = yield this.fillHistory(tx);
if (!info)
throw new Error('Info not found.');
for (i = 0; i < tx.inputs.length; i++) {
coin = coins[i];
path = yield this.getPath(coin);
details.addInput(i, path, coin);
}
return info.toDetails();
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
path = yield this.getPath(output);
details.addOutput(i, path);
}
return details;
});
/**
@ -2483,6 +2511,147 @@ function Orphan(tx, i) {
this.index = i;
}
function cmp(a, b) {
return a - b;
}
/**
* Transaction Details
* @constructor
* @param {PathInfo} info
*/
function Details(txdb, tx) {
if (!(this instanceof Details))
return new Details(txdb, tx);
this.db = txdb.walletdb;
this.network = this.db.network;
this.wid = txdb.wallet.wid;
this.id = txdb.wallet.id;
this.hash = tx.hash('hex');
this.height = tx.height;
this.block = tx.block;
this.index = tx.index;
this.confirmations = tx.getConfirmations(this.db.height);
this.fee = tx.getFee();
this.ts = tx.ts;
this.ps = tx.ps;
this.tx = tx;
this.inputs = [];
this.outputs = [];
this.accounts = [];
this.init();
}
Details.prototype.init = function init() {
var i, input, output, member;
for (i = 0; i < this.tx.inputs.length; i++) {
input = this.tx.inputs[i];
member = new DetailsMember();
member.address = input.getAddress();
this.inputs.push(member);
}
for (i = 0; i < this.tx.outputs.length; i++) {
output = this.tx.outputs[i];
member = new DetailsMember();
member.value = output.value;
member.address = output.getAddress();
this.outputs.push(member);
}
};
Details.prototype.addInput = function addInput(i, path, coin) {
var member = this.inputs[i];
if (coin) {
member.value = coin.value;
member.address = coin.getAddress();
}
if (path) {
member.path = path;
utils.binaryInsert(this.accounts, path.account, cmp, true);
}
};
Details.prototype.addOutput = function addOutput(i, path) {
var member = this.outputs[i];
if (path) {
member.path = path;
utils.binaryInsert(this.accounts, path.account, cmp, true);
}
};
/**
* Convert details to a more json-friendly object.
* @returns {Object}
*/
Details.prototype.toJSON = function toJSON() {
var self = this;
return {
wid: this.wid,
id: this.id,
hash: utils.revHex(this.hash),
height: this.height,
block: this.block ? utils.revHex(this.block) : null,
ts: this.ts,
ps: this.ps,
index: this.index,
fee: utils.btc(this.fee),
confirmations: this.confirmations,
inputs: this.inputs.map(function(input) {
return input.toJSON(self.network);
}),
outputs: this.outputs.map(function(output) {
return output.toJSON(self.network);
}),
tx: this.tx.toRaw().toString('hex')
};
};
/**
* Transaction Details Member
* @constructor
* @property {Number} value
* @property {Address} address
* @property {Path} path
*/
function DetailsMember() {
if (!(this instanceof DetailsMember))
return new DetailsMember();
this.value = 0;
this.address = null;
this.path = null;
}
/**
* Convert the member to a more json-friendly object.
* @param {Network} network
* @returns {Object}
*/
DetailsMember.prototype.toJSON = function toJSON(network) {
return {
value: utils.btc(this.value),
address: this.address
? this.address.toBase58(network)
: null,
path: this.path
? this.path.toJSON()
: null
};
};
/*
* Expose
*/

View File

@ -1622,14 +1622,20 @@ Wallet.prototype.getOutputPaths = co(function* getOutputPaths(tx) {
* (true if new addresses were allocated).
*/
Wallet.prototype.syncOutputDepth = co(function* syncOutputDepth(info) {
Wallet.prototype.syncOutputDepth = co(function* syncOutputDepth(details) {
var derived = [];
var accounts = {};
var i, j, path, paths, account;
var receive, change, nested, ring;
for (i = 0; i < info.paths.length; i++) {
path = info.paths[i];
if (!details)
return derived;
for (i = 0; i < details.outputs.length; i++) {
path = details.outputs[i].path;
if (!path)
continue;
if (path.index === -1)
continue;
@ -1842,14 +1848,13 @@ Wallet.prototype._add = co(function* add(tx) {
*/
Wallet.prototype._insert = co(function* insert(tx) {
var info = yield this.getPathInfo(tx);
var result, derived;
var details, derived;
this.txdb.start();
try {
result = yield this.txdb._add(tx, info);
derived = yield this.syncOutputDepth(info);
details = yield this.txdb._add(tx);
derived = yield this.syncOutputDepth(details);
} catch (e) {
this.txdb.drop();
throw e;
@ -1862,7 +1867,7 @@ Wallet.prototype._insert = co(function* insert(tx) {
this.emit('address', derived);
}
return result;
return details;
});
/**
@ -1986,27 +1991,6 @@ Wallet.prototype.getLocked = function getLocked() {
return this.txdb.getLocked();
};
/**
* Map a transactions' addresses to wallet IDs.
* @param {TX} tx
* @returns {Promise} - Returns {@link PathInfo}.
*/
Wallet.prototype.getPathInfo = co(function* getPathInfo(tx) {
var hashes = tx.getHashes('hex');
var paths = [];
var i, hash, path;
for (i = 0; i < hashes.length; i++) {
hash = hashes[i];
path = yield this.getPath(hash);
if (path)
paths.push(path);
}
return new PathInfo(this, tx, paths);
});
/**
* Get all transactions in transaction history (accesses db).
* @param {(String|Number)?} acct