mempool: refactor addr indexing.

This commit is contained in:
Christopher Jeffrey 2017-02-28 21:41:20 -08:00
parent d92d6487b5
commit 8cb2c4a1a0
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

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