mempool: refactor.
This commit is contained in:
parent
c9fbaae0da
commit
c300df7340
@ -140,14 +140,15 @@ Mempool.prototype._close = function close() {
|
|||||||
* Notify the mempool that a new block has come
|
* Notify the mempool that a new block has come
|
||||||
* in (removes all transactions contained in the
|
* in (removes all transactions contained in the
|
||||||
* block from the mempool).
|
* block from the mempool).
|
||||||
* @param {Block} block
|
* @param {ChainEntry} block
|
||||||
|
* @param {TX[]} txs
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype.addBlock = co(function* addBlock(block) {
|
Mempool.prototype.addBlock = co(function* addBlock(block, txs) {
|
||||||
var unlock = yield this.locker.lock();
|
var unlock = yield this.locker.lock();
|
||||||
try {
|
try {
|
||||||
return this._addBlock(block);
|
return this._addBlock(block, txs);
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
@ -157,16 +158,17 @@ Mempool.prototype.addBlock = co(function* addBlock(block) {
|
|||||||
* Notify the mempool that a new block
|
* Notify the mempool that a new block
|
||||||
* has come without a lock.
|
* has come without a lock.
|
||||||
* @private
|
* @private
|
||||||
* @param {Block} block
|
* @param {ChainEntry} block
|
||||||
|
* @param {TX[]} txs
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype._addBlock = function addBlock(block) {
|
Mempool.prototype._addBlock = function addBlock(block, txs) {
|
||||||
var entries = [];
|
var entries = [];
|
||||||
var i, entry, tx, hash;
|
var i, entry, tx, hash;
|
||||||
|
|
||||||
for (i = block.txs.length - 1; i >= 1; i--) {
|
for (i = txs.length - 1; i >= 1; i--) {
|
||||||
tx = block.txs[i];
|
tx = txs[i];
|
||||||
hash = tx.hash('hex');
|
hash = tx.hash('hex');
|
||||||
entry = this.getEntry(hash);
|
entry = this.getEntry(hash);
|
||||||
|
|
||||||
@ -175,7 +177,7 @@ Mempool.prototype._addBlock = function addBlock(block) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.removeUnchecked(entry);
|
this.removeEntry(entry);
|
||||||
this.emit('confirmed', tx, block);
|
this.emit('confirmed', tx, block);
|
||||||
|
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
@ -192,14 +194,15 @@ Mempool.prototype._addBlock = function addBlock(block) {
|
|||||||
/**
|
/**
|
||||||
* Notify the mempool that a block has been disconnected
|
* Notify the mempool that a block has been disconnected
|
||||||
* from the main chain (reinserts transactions into the mempool).
|
* from the main chain (reinserts transactions into the mempool).
|
||||||
* @param {Block} block
|
* @param {ChainEntry} block
|
||||||
|
* @param {TX[]} txs
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype.removeBlock = co(function* removeBlock(block) {
|
Mempool.prototype.removeBlock = co(function* removeBlock(block, txs) {
|
||||||
var unlock = yield this.locker.lock();
|
var unlock = yield this.locker.lock();
|
||||||
try {
|
try {
|
||||||
return this._removeBlock(block);
|
return this._removeBlock(block, txs);
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
@ -209,15 +212,16 @@ Mempool.prototype.removeBlock = co(function* removeBlock(block) {
|
|||||||
* Notify the mempool that a block
|
* Notify the mempool that a block
|
||||||
* has been disconnected without a lock.
|
* has been disconnected without a lock.
|
||||||
* @private
|
* @private
|
||||||
* @param {Block} block
|
* @param {ChainEntry} block
|
||||||
|
* @param {TX[]} txs
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype._removeBlock = function removeBlock(block) {
|
Mempool.prototype._removeBlock = function removeBlock(block, txs) {
|
||||||
var i, entry, tx, hash;
|
var i, entry, tx, hash;
|
||||||
|
|
||||||
for (i = 1; i < block.txs.length; i++) {
|
for (i = 1; i < txs.length; i++) {
|
||||||
tx = block.txs[i];
|
tx = txs[i];
|
||||||
hash = tx.hash('hex');
|
hash = tx.hash('hex');
|
||||||
|
|
||||||
if (this.hasTX(hash))
|
if (this.hasTX(hash))
|
||||||
@ -307,7 +311,7 @@ Mempool.prototype.limitMempoolSize = function limitMempoolSize(entryHash) {
|
|||||||
if (!trimmed && hash === entryHash)
|
if (!trimmed && hash === entryHash)
|
||||||
trimmed = true;
|
trimmed = true;
|
||||||
|
|
||||||
this.removeUnchecked(entry, true);
|
this.removeEntry(entry, true);
|
||||||
|
|
||||||
if (this.getSize() <= this.maxSize)
|
if (this.getSize() <= this.maxSize)
|
||||||
return trimmed;
|
return trimmed;
|
||||||
@ -325,7 +329,7 @@ Mempool.prototype.limitMempoolSize = function limitMempoolSize(entryHash) {
|
|||||||
if (!trimmed && hash === entryHash)
|
if (!trimmed && hash === entryHash)
|
||||||
trimmed = true;
|
trimmed = true;
|
||||||
|
|
||||||
this.removeUnchecked(entry, true);
|
this.removeEntry(entry, true);
|
||||||
|
|
||||||
if (this.getSize() <= this.maxSize)
|
if (this.getSize() <= this.maxSize)
|
||||||
return trimmed;
|
return trimmed;
|
||||||
@ -594,6 +598,9 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
|
|
||||||
assert(!tx.mutable, 'Cannot add mutable TX to mempool.');
|
assert(!tx.mutable, 'Cannot add mutable TX to mempool.');
|
||||||
|
|
||||||
|
// Basic sanity checks.
|
||||||
|
// This is important because it ensures
|
||||||
|
// other functions will be overflow safe.
|
||||||
if (!tx.isSane(ret)) {
|
if (!tx.isSane(ret)) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'invalid',
|
'invalid',
|
||||||
@ -601,6 +608,8 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
ret.score);
|
ret.score);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Coinbases are an insta-ban.
|
||||||
|
// Why? Who knows.
|
||||||
if (tx.isCoinbase()) {
|
if (tx.isCoinbase()) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'invalid',
|
'invalid',
|
||||||
@ -608,6 +617,7 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
100);
|
100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not allow CSV until it's activated.
|
||||||
if (this.requireStandard) {
|
if (this.requireStandard) {
|
||||||
if (!this.chain.state.hasCSV() && tx.version >= 2) {
|
if (!this.chain.state.hasCSV() && tx.version >= 2) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
@ -617,6 +627,7 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not allow segwit until it's activated.
|
||||||
if (!this.chain.state.hasWitness() && !this.prematureWitness) {
|
if (!this.chain.state.hasWitness() && !this.prematureWitness) {
|
||||||
if (tx.hasWitness()) {
|
if (tx.hasWitness()) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
@ -626,6 +637,7 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Non-contextual standardness checks.
|
||||||
if (this.requireStandard) {
|
if (this.requireStandard) {
|
||||||
if (!tx.isStandard(ret)) {
|
if (!tx.isStandard(ret)) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
@ -643,6 +655,7 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify transaction finality (see isFinal()).
|
||||||
if (!(yield this.verifyFinal(tx, lockFlags))) {
|
if (!(yield this.verifyFinal(tx, lockFlags))) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'nonstandard',
|
'nonstandard',
|
||||||
@ -650,6 +663,7 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can maybe ignore this.
|
||||||
if (this.exists(hash)) {
|
if (this.exists(hash)) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'alreadyknown',
|
'alreadyknown',
|
||||||
@ -657,6 +671,9 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can test whether this is an
|
||||||
|
// non-fully-spent transaction on
|
||||||
|
// the chain.
|
||||||
if (yield this.chain.db.hasCoins(hash)) {
|
if (yield this.chain.db.hasCoins(hash)) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'alreadyknown',
|
'alreadyknown',
|
||||||
@ -664,6 +681,9 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quick and dirty test to verify we're
|
||||||
|
// not double-spending an output in the
|
||||||
|
// mempool.
|
||||||
if (this.isDoubleSpend(tx)) {
|
if (this.isDoubleSpend(tx)) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'duplicate',
|
'duplicate',
|
||||||
@ -671,23 +691,30 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!(yield this.fillAllCoins(tx)))
|
// Get coin viewpoint as it
|
||||||
// return this.maybeStoreOrphan(tx);
|
// pertains to the mempool.
|
||||||
|
|
||||||
view = yield this.getCoinView(tx);
|
view = yield this.getCoinView(tx);
|
||||||
|
|
||||||
|
// Find missing outpoints.
|
||||||
missing = this.injectCoins(tx, view);
|
missing = this.injectCoins(tx, view);
|
||||||
|
|
||||||
|
// Maybe store as an orphan.
|
||||||
if (missing.length > 0) {
|
if (missing.length > 0) {
|
||||||
if (this.storeOrphan(tx, missing))
|
if (this.storeOrphan(tx, missing))
|
||||||
return missing;
|
return missing;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a mempool entry and
|
||||||
|
// begin contextual verification.
|
||||||
entry = MempoolEntry.fromTX(tx, this.chain.height);
|
entry = MempoolEntry.fromTX(tx, this.chain.height);
|
||||||
|
|
||||||
yield this.verify(entry);
|
yield this.verify(entry);
|
||||||
yield this._addUnchecked(entry);
|
|
||||||
|
|
||||||
|
// Add and index the entry.
|
||||||
|
yield this.addEntry(entry);
|
||||||
|
|
||||||
|
// Trim size if we're too big.
|
||||||
if (this.limitMempoolSize(hash)) {
|
if (this.limitMempoolSize(hash)) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'insufficientfee',
|
'insufficientfee',
|
||||||
@ -706,23 +733,7 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype.addUnchecked = co(function* addUnchecked(entry) {
|
Mempool.prototype.addEntry = co(function* addEntry(entry) {
|
||||||
var unlock = yield this.locker.lock();
|
|
||||||
try {
|
|
||||||
return yield this._addUnchecked(entry);
|
|
||||||
} finally {
|
|
||||||
unlock();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a transaction to the mempool without a lock.
|
|
||||||
* @private
|
|
||||||
* @param {MempoolEntry} entry
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Mempool.prototype._addUnchecked = co(function* addUnchecked(entry) {
|
|
||||||
var i, resolved, tx;
|
var i, resolved, tx;
|
||||||
|
|
||||||
this.trackEntry(entry);
|
this.trackEntry(entry);
|
||||||
@ -757,7 +768,7 @@ Mempool.prototype._addUnchecked = co(function* addUnchecked(entry) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.spam('Resolved orphan %s in mempool.', tx.txid());
|
this.logger.debug('Resolved orphan %s in mempool.', tx.txid());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -768,7 +779,7 @@ Mempool.prototype._addUnchecked = co(function* addUnchecked(entry) {
|
|||||||
* @param {Boolean} limit
|
* @param {Boolean} limit
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype.removeUnchecked = function removeUnchecked(entry, limit) {
|
Mempool.prototype.removeEntry = function removeEntry(entry, limit) {
|
||||||
var tx = entry.tx;
|
var tx = entry.tx;
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
|
|
||||||
@ -810,6 +821,7 @@ Mempool.prototype.verify = co(function* verify(entry) {
|
|||||||
var ret = new VerifyResult();
|
var ret = new VerifyResult();
|
||||||
var now, minFee, result;
|
var now, minFee, result;
|
||||||
|
|
||||||
|
// Verify sequence locks.
|
||||||
if (!(yield this.verifyLocks(tx, lockFlags))) {
|
if (!(yield this.verifyLocks(tx, lockFlags))) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'nonstandard',
|
'nonstandard',
|
||||||
@ -817,6 +829,7 @@ Mempool.prototype.verify = co(function* verify(entry) {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check input an witness standardness.
|
||||||
if (this.requireStandard) {
|
if (this.requireStandard) {
|
||||||
if (!tx.hasStandardInputs()) {
|
if (!tx.hasStandardInputs()) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
@ -836,6 +849,7 @@ Mempool.prototype.verify = co(function* verify(entry) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Annoying process known as sigops counting.
|
||||||
if (tx.getSigopsWeight(flags) > constants.tx.MAX_SIGOPS_WEIGHT) {
|
if (tx.getSigopsWeight(flags) > constants.tx.MAX_SIGOPS_WEIGHT) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'nonstandard',
|
'nonstandard',
|
||||||
@ -843,6 +857,7 @@ Mempool.prototype.verify = co(function* verify(entry) {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure this guy gave a decent fee.
|
||||||
minFee = tx.getMinFee(entry.size, this.minRelay);
|
minFee = tx.getMinFee(entry.size, this.minRelay);
|
||||||
|
|
||||||
if (this.relayPriority && entry.fee < minFee) {
|
if (this.relayPriority && entry.fee < minFee) {
|
||||||
@ -855,19 +870,16 @@ Mempool.prototype.verify = co(function* verify(entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Continuously rate-limit free (really, very-low-fee)
|
// Continuously rate-limit free (really, very-low-fee)
|
||||||
// transactions. This mitigates 'penny-flooding'. i.e.
|
// transactions. This mitigates 'penny-flooding'.
|
||||||
// sending thousands of free transactions just to be
|
|
||||||
// annoying or make others' transactions take longer
|
|
||||||
// to confirm.
|
|
||||||
if (this.limitFree && entry.fee < minFee) {
|
if (this.limitFree && entry.fee < minFee) {
|
||||||
now = util.now();
|
now = util.now();
|
||||||
|
|
||||||
// Use an exponentially decaying ~10-minute window:
|
// Use an exponentially decaying ~10-minute window.
|
||||||
this.freeCount *= Math.pow(1 - 1 / 600, now - this.lastTime);
|
this.freeCount *= Math.pow(1 - 1 / 600, now - this.lastTime);
|
||||||
this.lastTime = now;
|
this.lastTime = now;
|
||||||
|
|
||||||
// The limitFreeRelay unit is thousand-bytes-per-minute
|
// The limitFreeRelay unit is thousand-bytes-per-minute
|
||||||
// At default rate it would take over a month to fill 1GB
|
// At default rate it would take over a month to fill 1GB.
|
||||||
if (this.freeCount > this.limitFreeRelay * 10 * 1000) {
|
if (this.freeCount > this.limitFreeRelay * 10 * 1000) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'insufficientfee',
|
'insufficientfee',
|
||||||
@ -878,9 +890,11 @@ Mempool.prototype.verify = co(function* verify(entry) {
|
|||||||
this.freeCount += entry.size;
|
this.freeCount += entry.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Important safety feature.
|
||||||
if (this.rejectAbsurdFees && entry.fee > minFee * 10000)
|
if (this.rejectAbsurdFees && entry.fee > minFee * 10000)
|
||||||
throw new VerifyError(tx, 'highfee', 'absurdly-high-fee', 0);
|
throw new VerifyError(tx, 'highfee', 'absurdly-high-fee', 0);
|
||||||
|
|
||||||
|
// Why do we have this here? Nested transactions are cool.
|
||||||
if (this.countAncestors(tx) > this.maxAncestors) {
|
if (this.countAncestors(tx) > this.maxAncestors) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'nonstandard',
|
'nonstandard',
|
||||||
@ -888,10 +902,11 @@ Mempool.prototype.verify = co(function* verify(entry) {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Contextual sanity checks.
|
||||||
if (!tx.checkInputs(height, ret))
|
if (!tx.checkInputs(height, ret))
|
||||||
throw new VerifyError(tx, 'invalid', ret.reason, ret.score);
|
throw new VerifyError(tx, 'invalid', ret.reason, ret.score);
|
||||||
|
|
||||||
// Standard verification
|
// Script verification.
|
||||||
try {
|
try {
|
||||||
yield this.verifyInputs(tx, flags1);
|
yield this.verifyInputs(tx, flags1);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -1405,8 +1420,8 @@ Mempool.prototype.resolveOrphans = function resolveOrphans(tx) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (--orphan.missing === 0) {
|
if (--orphan.missing === 0) {
|
||||||
this.totalOrphans--;
|
|
||||||
delete this.orphans[orphanHash];
|
delete this.orphans[orphanHash];
|
||||||
|
this.totalOrphans--;
|
||||||
try {
|
try {
|
||||||
resolved.push(orphan.toTX());
|
resolved.push(orphan.toTX());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -1438,9 +1453,11 @@ Mempool.prototype.removeOrphan = function removeOrphan(hash) {
|
|||||||
tx = orphan.toTX();
|
tx = orphan.toTX();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
delete this.orphans[hash];
|
delete this.orphans[hash];
|
||||||
|
this.totalOrphans--;
|
||||||
this.logger.warning('%s %s',
|
this.logger.warning('%s %s',
|
||||||
'Warning: possible memory corruption.',
|
'Warning: possible memory corruption.',
|
||||||
'Orphan failed deserialization.');
|
'Orphan failed deserialization.');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prevout = tx.getPrevout();
|
prevout = tx.getPrevout();
|
||||||
@ -1465,10 +1482,9 @@ Mempool.prototype.removeOrphan = function removeOrphan(hash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete this.orphans[hash];
|
delete this.orphans[hash];
|
||||||
|
this.totalOrphans--;
|
||||||
|
|
||||||
this.emit('remove orphan', tx);
|
this.emit('remove orphan', tx);
|
||||||
|
|
||||||
this.totalOrphans--;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1585,7 +1601,7 @@ Mempool.prototype.fillAllHistory = function fillAllHistory(tx) {
|
|||||||
if (tx.hasCoins())
|
if (tx.hasCoins())
|
||||||
return Promise.resolve(tx);
|
return Promise.resolve(tx);
|
||||||
|
|
||||||
return this.chain.db.fillCoins(tx);
|
return this.chain.db.fillHistory(tx);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1809,7 +1825,7 @@ Mempool.prototype.removeSpenders = function removeSpenders(entry) {
|
|||||||
if (!spender)
|
if (!spender)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
this.removeUnchecked(spender, true);
|
this.removeEntry(spender, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -208,14 +208,14 @@ FullNode.prototype._init = function _init() {
|
|||||||
self.emit('connect', entry, block);
|
self.emit('connect', entry, block);
|
||||||
|
|
||||||
if (self.chain.synced)
|
if (self.chain.synced)
|
||||||
self.mempool.addBlock(block).catch(onError);
|
self.mempool.addBlock(entry, block.txs).catch(onError);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.chain.on('disconnect', function(entry, block) {
|
this.chain.on('disconnect', function(entry, block) {
|
||||||
self.emit('disconnect', entry, block);
|
self.emit('disconnect', entry, block);
|
||||||
|
|
||||||
if (self.chain.synced)
|
if (self.chain.synced)
|
||||||
self.mempool.removeBlock(block).catch(onError);
|
self.mempool.removeBlock(entry, block.txs).catch(onError);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.chain.on('reset', function(tip) {
|
this.chain.on('reset', function(tip) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user