txdb: more atomicity for double-spender removal.
This commit is contained in:
parent
aa8f9fdf90
commit
a800f8c44b
@ -633,15 +633,22 @@ TXDB.prototype._add = co(function* add(tx, info) {
|
|||||||
if (result)
|
if (result)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
this.start();
|
||||||
|
|
||||||
// Verify and get coins.
|
// Verify and get coins.
|
||||||
result = yield this.verify(tx, info);
|
// This potentially removes double-spenders.
|
||||||
|
try {
|
||||||
|
result = yield this.verify(tx, info);
|
||||||
|
} catch (e) {
|
||||||
|
this.drop();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
hash = tx.hash('hex');
|
hash = tx.hash('hex');
|
||||||
|
|
||||||
this.start();
|
|
||||||
this.put(layout.t(hash), tx.toExtended());
|
this.put(layout.t(hash), tx.toExtended());
|
||||||
|
|
||||||
if (tx.ts === 0)
|
if (tx.ts === 0)
|
||||||
@ -804,41 +811,38 @@ TXDB.prototype.removeConflict = co(function* removeConflict(hash, ref) {
|
|||||||
* @returns {Promise} - Returns Boolean.
|
* @returns {Promise} - Returns Boolean.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TXDB.prototype.removeRecursive = co(function* removeRecursive(tx) {
|
TXDB.prototype.removeRecursive = co(function* removeRecursive(tx, removed) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var i, spent, stx, info;
|
var i, spent, stx, info;
|
||||||
|
|
||||||
|
if (!removed)
|
||||||
|
removed = {};
|
||||||
|
|
||||||
for (i = 0; i < tx.outputs.length; i++) {
|
for (i = 0; i < tx.outputs.length; i++) {
|
||||||
spent = yield this.isSpent(hash, i);
|
spent = yield this.isSpent(hash, i);
|
||||||
|
|
||||||
if (!spent)
|
if (!spent)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (removed[spent.hash])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
removed[spent.hash] = true;
|
||||||
|
|
||||||
// Remove all of the spender's spenders first.
|
// Remove all of the spender's spenders first.
|
||||||
stx = yield this.getTX(spent.hash);
|
stx = yield this.getTX(spent.hash);
|
||||||
|
|
||||||
if (!stx)
|
if (!stx)
|
||||||
throw new Error('Could not find spender.');
|
throw new Error('Could not find spender.');
|
||||||
|
|
||||||
yield this.removeRecursive(stx);
|
yield this.removeRecursive(stx, removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.start();
|
|
||||||
|
|
||||||
// Remove the spender.
|
// Remove the spender.
|
||||||
try {
|
info = yield this.lazyRemove(tx);
|
||||||
info = yield this.lazyRemove(tx);
|
|
||||||
} catch (e) {
|
|
||||||
this.drop();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info) {
|
if (!info)
|
||||||
this.drop();
|
|
||||||
throw new Error('Cannot remove spender.');
|
throw new Error('Cannot remove spender.');
|
||||||
}
|
|
||||||
|
|
||||||
yield this.commit();
|
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
});
|
});
|
||||||
@ -1008,7 +1012,16 @@ TXDB.prototype._remove = co(function* remove(hash) {
|
|||||||
if (!tx)
|
if (!tx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
info = yield this.removeRecursive(tx);
|
this.start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
info = yield this.removeRecursive(tx);
|
||||||
|
} catch (e) {
|
||||||
|
this.drop();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield this.commit();
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -72,7 +72,7 @@ function Wallet(db, options) {
|
|||||||
this.indexCache = new LRU(10000);
|
this.indexCache = new LRU(10000);
|
||||||
this.accountCache = new LRU(10000);
|
this.accountCache = new LRU(10000);
|
||||||
this.pathCache = new LRU(100000);
|
this.pathCache = new LRU(100000);
|
||||||
this.batch = null;
|
this.current = null;
|
||||||
|
|
||||||
this.wid = 0;
|
this.wid = 0;
|
||||||
this.id = null;
|
this.id = null;
|
||||||
|
|||||||
@ -144,7 +144,6 @@ function WalletDB(options) {
|
|||||||
this.network = Network.get(options.network);
|
this.network = Network.get(options.network);
|
||||||
this.fees = options.fees;
|
this.fees = options.fees;
|
||||||
this.logger = options.logger || Logger.global;
|
this.logger = options.logger || Logger.global;
|
||||||
this.batches = {};
|
|
||||||
this.wallets = {};
|
this.wallets = {};
|
||||||
|
|
||||||
this.tip = this.network.genesis.hash;
|
this.tip = this.network.genesis.hash;
|
||||||
@ -292,9 +291,9 @@ WalletDB.prototype.getDepth = co(function* getDepth() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.start = function start(wallet) {
|
WalletDB.prototype.start = function start(wallet) {
|
||||||
assert(!wallet.batch, 'Batch already started.');
|
assert(!wallet.current, 'Batch already started.');
|
||||||
wallet.batch = this.db.batch();
|
wallet.current = this.db.batch();
|
||||||
return wallet.batch;
|
return wallet.current;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -305,7 +304,7 @@ WalletDB.prototype.start = function start(wallet) {
|
|||||||
|
|
||||||
WalletDB.prototype.drop = function drop(wallet) {
|
WalletDB.prototype.drop = function drop(wallet) {
|
||||||
var batch = this.batch(wallet);
|
var batch = this.batch(wallet);
|
||||||
wallet.batch = null;
|
wallet.current = null;
|
||||||
batch.clear();
|
batch.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -317,8 +316,8 @@ WalletDB.prototype.drop = function drop(wallet) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.batch = function batch(wallet) {
|
WalletDB.prototype.batch = function batch(wallet) {
|
||||||
assert(wallet.batch, 'Batch does not exist.');
|
assert(wallet.current, 'Batch does not exist.');
|
||||||
return wallet.batch;
|
return wallet.current;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -329,8 +328,8 @@ WalletDB.prototype.batch = function batch(wallet) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
WalletDB.prototype.commit = function commit(wallet) {
|
WalletDB.prototype.commit = function commit(wallet) {
|
||||||
var batch = wallet.batch;
|
var batch = wallet.current;
|
||||||
wallet.batch = null;
|
wallet.current = null;
|
||||||
return batch.write();
|
return batch.write();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user