mempool: sanitize after reorg.

This commit is contained in:
Christopher Jeffrey 2017-09-26 17:20:16 -07:00
parent 459a9f25f4
commit 1aa78e2248
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
5 changed files with 81 additions and 8 deletions

View File

@ -905,7 +905,7 @@ Chain.prototype.reorganize = async function reorganize(competitor) {
competitor.height competitor.height
); );
this.emit('reorganize', tip, competitor); await this.fire('reorganize', tip, competitor);
}; };
/** /**
@ -957,7 +957,7 @@ Chain.prototype.reorganizeSPV = async function reorganizeSPV(competitor) {
'Chain replay from height %d necessary.', 'Chain replay from height %d necessary.',
fork.height); fork.height);
this.emit('reorganize', tip, competitor); await this.fire('reorganize', tip, competitor);
}; };
/** /**

View File

@ -10,6 +10,7 @@ const assert = require('assert');
const path = require('path'); const path = require('path');
const AsyncObject = require('../utils/asyncobject'); const AsyncObject = require('../utils/asyncobject');
const common = require('../blockchain/common'); const common = require('../blockchain/common');
const consensus = require('../protocol/consensus');
const policy = require('../protocol/policy'); const policy = require('../protocol/policy');
const util = require('../utils/util'); const util = require('../utils/util');
const random = require('../crypto/random'); const random = require('../crypto/random');
@ -198,8 +199,9 @@ Mempool.prototype._addBlock = async function _addBlock(block, txs) {
if (!entry) { if (!entry) {
this.removeOrphan(hash); this.removeOrphan(hash);
this.resolveOrphans(tx);
this.removeDoubleSpends(tx); this.removeDoubleSpends(tx);
if (this.waiting.has(hash))
await this.handleOrphans(tx);
continue; continue;
} }
@ -303,6 +305,55 @@ Mempool.prototype._removeBlock = async function _removeBlock(block, txs) {
total, block.height); total, block.height);
}; };
/**
* Sanitize the mempool after a reorg.
* @private
* @returns {Promise}
*/
Mempool.prototype._handleReorg = async function _handleReorg() {
const height = this.chain.height + 1;
const mtp = await this.chain.getMedianTime(this.chain.tip);
const remove = [];
for (const [hash, entry] of this.map) {
const {tx} = entry;
if (!tx.isFinal(height, mtp)) {
remove.push(hash);
continue;
}
if (tx.version > 1) {
let hasLocks = false;
for (const {sequence} of tx.inputs) {
if (!(sequence & consensus.SEQUENCE_DISABLE_FLAG)) {
hasLocks = true;
break;
}
}
if (hasLocks) {
remove.push(hash);
continue;
}
}
if (entry.coinbase)
remove.push(hash);
}
for (const hash of remove) {
const entry = this.getEntry(hash);
if (!entry)
continue;
this.evictEntry(entry);
}
};
/** /**
* Reset the mempool. * Reset the mempool.
* @method * @method

View File

@ -43,6 +43,7 @@ function MempoolEntry(options) {
this.deltaFee = 0; this.deltaFee = 0;
this.time = 0; this.time = 0;
this.value = 0; this.value = 0;
this.coinbase = false;
this.dependencies = false; this.dependencies = false;
this.descFee = 0; this.descFee = 0;
this.descSize = 0; this.descSize = 0;
@ -67,6 +68,7 @@ MempoolEntry.prototype.fromOptions = function fromOptions(options) {
this.deltaFee = options.deltaFee; this.deltaFee = options.deltaFee;
this.time = options.time; this.time = options.time;
this.value = options.value; this.value = options.value;
this.coinbase = options.coinbase;
this.dependencies = options.dependencies; this.dependencies = options.dependencies;
this.descFee = options.descFee; this.descFee = options.descFee;
this.descSize = options.descSize; this.descSize = options.descSize;
@ -99,11 +101,14 @@ MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) {
const fee = tx.getFee(view); const fee = tx.getFee(view);
let dependencies = false; let dependencies = false;
let coinbase = false;
for (const {prevout} of tx.inputs) { for (const {prevout} of tx.inputs) {
if (view.getHeight(prevout) === -1) { if (view.isCoinbase(prevout))
coinbase = true;
if (view.getHeight(prevout) === -1)
dependencies = true; dependencies = true;
break;
}
} }
this.tx = tx; this.tx = tx;
@ -115,6 +120,7 @@ MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) {
this.deltaFee = fee; this.deltaFee = fee;
this.time = util.now(); this.time = util.now();
this.value = value; this.value = value;
this.coinbase = coinbase;
this.dependencies = dependencies; this.dependencies = dependencies;
this.descFee = fee; this.descFee = fee;
this.descSize = size; this.descSize = size;
@ -229,6 +235,7 @@ MempoolEntry.prototype.memUsage = function memUsage() {
let total = 0; let total = 0;
total += 176; // mempool entry total += 176; // mempool entry
total += 48; // coinbase
total += 48; // dependencies total += 48; // dependencies
total += 208; // tx total += 208; // tx
@ -297,7 +304,7 @@ MempoolEntry.prototype.isFree = function isFree(height) {
*/ */
MempoolEntry.prototype.getSize = function getSize() { MempoolEntry.prototype.getSize = function getSize() {
return this.tx.getSize() + 41; return this.tx.getSize() + 42;
}; };
/** /**
@ -315,6 +322,7 @@ MempoolEntry.prototype.toRaw = function toRaw() {
bw.writeU64(this.fee); bw.writeU64(this.fee);
bw.writeU32(this.time); bw.writeU32(this.time);
bw.writeU64(this.value); bw.writeU64(this.value);
bw.writeU8(this.coinbase ? 1 : 0);
bw.writeU8(this.dependencies ? 1 : 0); bw.writeU8(this.dependencies ? 1 : 0);
return bw.render(); return bw.render();
}; };
@ -337,6 +345,7 @@ MempoolEntry.prototype.fromRaw = function fromRaw(data) {
this.deltaFee = this.fee; this.deltaFee = this.fee;
this.time = br.readU32(); this.time = br.readU32();
this.value = br.readU64(); this.value = br.readU64();
this.coinbase = br.readU8() === 1;
this.dependencies = br.readU8() === 1; this.dependencies = br.readU8() === 1;
this.descFee = this.fee; this.descFee = this.fee;
this.descSize = this.size; this.descSize = this.size;

View File

@ -197,6 +197,15 @@ FullNode.prototype._init = function _init() {
this.emit('disconnect', entry, block); this.emit('disconnect', entry, block);
}); });
this.chain.hook('reorganize', async (tip, competitor) => {
try {
await this.mempool._handleReorg();
} catch (e) {
this.error(e);
}
this.emit('reorganize', tip, competitor);
});
this.chain.hook('reset', async (tip) => { this.chain.hook('reset', async (tip) => {
try { try {
await this.mempool._reset(); await this.mempool._reset();

View File

@ -143,7 +143,11 @@ SPVNode.prototype._init = function _init() {
}); });
this.chain.on('disconnect', (entry, block) => { this.chain.on('disconnect', (entry, block) => {
this.emit('disconnect', entry); this.emit('disconnect', entry, block);
});
this.chain.on('reorganize', (tip, competitor) => {
this.emit('reorganize', tip, competitor);
}); });
this.chain.on('reset', (tip) => { this.chain.on('reset', (tip) => {