From 8cb2c4a1a0e628efd956586eccada47ae26aad01 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 28 Feb 2017 21:41:20 -0800 Subject: [PATCH] mempool: refactor addr indexing. --- lib/mempool/mempool.js | 162 +++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 71 deletions(-) diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 606074f5..8181c9d7 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -28,6 +28,7 @@ var encoding = require('../utils/encoding'); var layout = require('./layout'); var LDB = require('../db/ldb'); var Fees = require('./fees'); +var Map = require('../utils/map'); var VerifyError = errors.VerifyError; var VerifyResult = errors.VerifyResult; @@ -92,8 +93,8 @@ function Mempool(options) { this.spents = {}; this.rejects = new Bloom.Rolling(120000, 0.000001); - this.coinIndex = new CoinIndex(this); - this.txIndex = new TXIndex(this); + this.coinIndex = new CoinIndex(); + this.txIndex = new TXIndex(); } util.inherits(Mempool, AsyncObject); @@ -107,7 +108,7 @@ util.inherits(Mempool, AsyncObject); Mempool.prototype._open = co(function* open() { var size = (this.options.maxSize / 1024).toFixed(2); - var i, entries, entry, fees; + var i, entries, entry, view, fees; yield this.chain.open(); yield this.cache.open(); @@ -122,7 +123,13 @@ Mempool.prototype._open = co(function* open() { for (i = 0; i < entries.length; i++) { entry = entries[i]; + this.updateAncestors(entry); + + if (this.options.indexAddress) { + view = yield this.getCoinView(entry.tx); + this.indexEntry(entry, view); + } } this.logger.info( @@ -1704,10 +1711,8 @@ Mempool.prototype.trackEntry = function trackEntry(entry, view) { this.spents[key] = entry; } - if (this.options.indexAddress) { - assert(view, 'No view passed to trackEntry.'); + if (this.options.indexAddress && view) this.indexEntry(entry, view); - } this.size += entry.memUsage(); this.totalTX++; @@ -1751,13 +1756,14 @@ Mempool.prototype.untrackEntry = function untrackEntry(entry) { Mempool.prototype.indexEntry = function indexEntry(entry, view) { var tx = entry.tx; - var i, input; + var i, input, prev; - this.txIndex.insert(tx, view); + this.txIndex.insert(entry, view); for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; - this.coinIndex.remove(input.prevout); + prev = input.prevout; + this.coinIndex.remove(prev.hash, prev.index); } for (i = 0; i < tx.outputs.length; i++) @@ -1772,9 +1778,10 @@ Mempool.prototype.indexEntry = function indexEntry(entry, view) { Mempool.prototype.unindexEntry = function unindexEntry(entry) { var tx = entry.tx; + var hash = tx.hash('hex'); var i, input, prevout, prev; - this.txIndex.remove(tx); + this.txIndex.remove(hash); for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; @@ -1787,10 +1794,8 @@ Mempool.prototype.unindexEntry = function unindexEntry(entry) { this.coinIndex.insert(prev, prevout.index); } - for (i = 0; i < tx.outputs.length; i++) { - prevout = Outpoint.fromTX(tx, i); - this.coinIndex.remove(prevout); - } + for (i = 0; i < tx.outputs.length; i++) + this.coinIndex.remove(hash, i); }; /** @@ -2015,8 +2020,6 @@ MempoolOptions.prototype.fromOptions = function fromOptions(options) { if (options.persistent != null) { assert(typeof options.persistent === 'boolean'); this.persistent = options.persistent; - assert(this.persistent !== this.indexAddress, - 'Cannot have persistent mempool with address indexing.'); } return this; @@ -2036,13 +2039,10 @@ MempoolOptions.fromOptions = function fromOptions(options) { * TX Address Index * @constructor * @ignore - * @param {Mempool} mempool */ -function TXIndex(mempool) { - this.mempool = mempool; - - // Map of addr->txids. +function TXIndex() { + // Map of addr->entries. this.index = {}; // Map of txid->addrs. @@ -2057,16 +2057,16 @@ TXIndex.prototype.reset = function reset() { TXIndex.prototype.get = function get(addr) { var items = this.index[addr]; var out = []; - var i, hash, tx; + var i, keys, entry; if (!items) return out; - for (i = 0; i < items.length; i++) { - hash = items[i].toString('hex'); - tx = this.mempool.getTX(hash); - assert(tx); - out.push(tx); + keys = items.keys(); + + for (i = 0; i < keys.length; i++) { + entry = items.get(keys[i]); + out.push(entry.tx); } return out; @@ -2075,44 +2075,50 @@ TXIndex.prototype.get = function get(addr) { TXIndex.prototype.getMeta = function getMeta(addr) { var items = this.index[addr]; var out = []; - var i, hash, tx; + var i, entry, keys, meta; if (!items) return out; - for (i = 0; i < items.length; i++) { - hash = items[i].toString('hex'); - tx = this.mempool.getMeta(hash); - assert(tx); - out.push(tx); + keys = items.keys(); + + for (i = 0; i < keys.length; i++) { + entry = items.get(keys[i]); + meta = TXMeta.fromTX(entry.tx); + meta.ps = entry.ts; + out.push(meta); } return out; }; -TXIndex.prototype.insert = function insert(tx, view) { - var key = tx.hash('hex'); +TXIndex.prototype.insert = function insert(entry, view) { + var tx = entry.tx; + var hash = tx.hash('hex'); var addrs = tx.getHashes(view, 'hex'); var i, addr, items; + if (addrs.length === 0) + return; + for (i = 0; i < addrs.length; i++) { addr = addrs[i]; items = this.index[addr]; if (!items) { - items = []; + items = new Map(); this.index[addr] = items; } - util.binaryInsert(items, tx.hash(), util.cmp); + assert(!items.has(hash)); + items.set(hash, entry); } - this.map[key] = addrs; + this.map[hash] = addrs; }; -TXIndex.prototype.remove = function remove(tx) { - var key = tx.hash('hex'); - var addrs = this.map[key]; +TXIndex.prototype.remove = function remove(hash) { + var addrs = this.map[hash]; var i, addr, items; if (!addrs) @@ -2122,29 +2128,26 @@ TXIndex.prototype.remove = function remove(tx) { addr = addrs[i]; items = this.index[addr]; - if (!items) - continue; + assert(items); + assert(items.has(hash)); - util.binaryRemove(items, tx.hash(), util.cmp); + items.remove(hash); - if (items.length === 0) + if (items.size === 0) delete this.index[addr]; } - delete this.map[key]; + delete this.map[hash]; }; /** * Coin Address Index * @constructor * @ignore - * @param {Mempool} mempool */ -function CoinIndex(mempool) { - this.mempool = mempool; - - // Map of addr->outpoints. +function CoinIndex() { + // Map of addr->coins. this.index = {}; // Map of outpoint->addr. @@ -2159,26 +2162,27 @@ CoinIndex.prototype.reset = function reset() { CoinIndex.prototype.get = function get(addr) { var items = this.index[addr]; var out = []; - var i, item, outpoint, coin; + var i, keys, coin; if (!items) return out; - for (i = 0; i < items.length; i++) { - item = items[i]; - outpoint = Outpoint.fromRaw(item); - coin = this.mempool.getCoin(outpoint.hash, outpoint.index); + keys = items.keys(); + + for (i = 0; i < keys.length; i++) { + coin = items.get(keys[i]); assert(coin); - out.push(coin); + out.push(coin.toCoin()); } return out; }; -CoinIndex.prototype.insert = function insert(tx, i) { - var output = tx.outputs[i]; +CoinIndex.prototype.insert = function insert(tx, index) { + var output = tx.outputs[index]; + var hash = tx.hash('hex'); var addr = output.getHash('hex'); - var items, outpoint, key; + var items, key; if (!addr) return; @@ -2186,20 +2190,20 @@ CoinIndex.prototype.insert = function insert(tx, i) { items = this.index[addr]; if (!items) { - items = []; + items = new Map(); this.index[addr] = items; } - outpoint = Outpoint.fromTX(tx, i); - key = outpoint.toKey(); + key = Outpoint.toKey(hash, index); - util.binaryInsert(items, outpoint.toRaw(), util.cmp); + assert(!items.has(key)); + items.set(key, new IndexedCoin(tx, index)); this.map[key] = addr; }; -CoinIndex.prototype.remove = function remove(outpoint) { - var key = outpoint.toKey(); +CoinIndex.prototype.remove = function remove(hash, index) { + var key = Outpoint.toKey(hash, index); var addr = this.map[key]; var items; @@ -2208,17 +2212,33 @@ CoinIndex.prototype.remove = function remove(outpoint) { items = this.index[addr]; - if (!items) - return; + assert(items); + assert(items.has(key)); + items.remove(key); - util.binaryRemove(items, outpoint.toRaw(), util.cmp); - - if (items.length === 0) + if (items.size === 0) delete this.index[addr]; delete this.map[key]; }; +/** + * IndexedCoin + * @constructor + * @ignore + * @param {TX} tx + * @param {Number} index + */ + +function IndexedCoin(tx, index) { + this.tx = tx; + this.index = index; +} + +IndexedCoin.prototype.toCoin = function toCoin() { + return Coin.fromTX(this.tx, this.index, -1); +}; + /** * Orphan * @constructor