map addresses to ids.
This commit is contained in:
parent
434fdc7a78
commit
ef55d1cebc
@ -37,7 +37,7 @@ function Chain(node, options) {
|
||||
this.loading = false;
|
||||
this.mempool = node.mempool;
|
||||
this.blockdb = node.blockdb;
|
||||
this.db = new bcoin.chaindb(node, this);
|
||||
this.db = new bcoin.chaindb(node, this, options);
|
||||
this.busy = false;
|
||||
this.jobs = [];
|
||||
this.pending = [];
|
||||
|
||||
@ -35,8 +35,13 @@ function ChainDB(node, chain, options) {
|
||||
this.chain = chain;
|
||||
this.file = options.file;
|
||||
|
||||
if (!this.file)
|
||||
this.file = bcoin.prefix + '/chain-' + network.type + '.db';
|
||||
if (!this.file) {
|
||||
this.file = bcoin.prefix
|
||||
+ '/chain-'
|
||||
+ (options.spv ? 'spv-' : '')
|
||||
+ network.type
|
||||
+ '.db';
|
||||
}
|
||||
|
||||
this.heightLookup = {};
|
||||
this.queue = {};
|
||||
|
||||
@ -30,6 +30,7 @@ function TXPool(prefix, db, options) {
|
||||
this.options = options;
|
||||
this.busy = false;
|
||||
this.jobs = [];
|
||||
this.ids = true;
|
||||
|
||||
if (options.addressFilter)
|
||||
this._hasAddress = options.addressFilter;
|
||||
@ -85,32 +86,111 @@ TXPool.prototype.add = function add(tx, callback) {
|
||||
}, callback);
|
||||
}
|
||||
|
||||
return self._add(tx, callback);
|
||||
//if (!this.ids)
|
||||
return this._add(tx, this.__getIDs(tx), callback);
|
||||
|
||||
return self._getIDs(tx.getAddresses(), function(err, ids) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return self._add(tx, ids, callback);
|
||||
});
|
||||
};
|
||||
|
||||
TXPool.prototype._hasAddress = function _hasAddress(address, callback) {
|
||||
if (!address)
|
||||
// Map of address->id.
|
||||
TXPool.prototype.__getIDs = function _getIDs(tx, callback) {
|
||||
var map = tx.getAddresses();
|
||||
return map.reduce(function(out, addr) {
|
||||
out[addr] = [addr];
|
||||
return out;
|
||||
}, {});
|
||||
};
|
||||
|
||||
TXPool.prototype.__hasAddress = function __hasAddress(map, address, callback) {
|
||||
if (!address || !map[address] || !map[address].length)
|
||||
return callback(null, false);
|
||||
return callback(null, true);
|
||||
};
|
||||
|
||||
TXPool.prototype._getIDs = function getIDs(address, callback) {
|
||||
var p = this.prefix + '/';
|
||||
var self = this;
|
||||
var map = {};
|
||||
|
||||
if (Array.isArray(address)) {
|
||||
address = utils.uniqs(address);
|
||||
return utils.forEachSerial(address, function(address, next) {
|
||||
self._getIDs(address, function(err, m) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
map[address] = m[address];
|
||||
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, map);
|
||||
});
|
||||
}
|
||||
|
||||
var iter = this.db.db.iterator({
|
||||
gte: p + 'a/' + address,
|
||||
lte: p + 'a/' + address + '~',
|
||||
keys: true,
|
||||
values: false,
|
||||
fillCache: false,
|
||||
keyAsBuffer: false
|
||||
});
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
map[address] = [];
|
||||
|
||||
(function next() {
|
||||
iter.next(function(err, key, value) {
|
||||
if (err) {
|
||||
return iter.end(function() {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
if (key === undefined) {
|
||||
return iter.end(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
map[address] = utils.uniqs(map[address]);
|
||||
return callback(null, map);
|
||||
});
|
||||
}
|
||||
|
||||
map[address].push(key.split('/')[3]);
|
||||
|
||||
next();
|
||||
});
|
||||
})();
|
||||
};
|
||||
|
||||
// This big scary function is what a persistent tx pool
|
||||
// looks like. It's a semi mempool in that it can handle
|
||||
// receiving txs out of order.
|
||||
TXPool.prototype._add = function add(tx, callback, force) {
|
||||
TXPool.prototype._add = function add(tx, map, callback, force) {
|
||||
var self = this;
|
||||
var p = this.prefix + '/';
|
||||
var hash = tx.hash('hex');
|
||||
var updated = false;
|
||||
var own = false;
|
||||
var uniq = {};
|
||||
var batch;
|
||||
|
||||
var unlock = this._lock(add, [tx, callback], force);
|
||||
if (!unlock)
|
||||
return;
|
||||
// var unlock = this._lock(add, [tx, map, callback], force);
|
||||
// if (!unlock)
|
||||
// return;
|
||||
|
||||
function done(err, result) {
|
||||
unlock();
|
||||
//unlock();
|
||||
if (callback)
|
||||
callback(err, result);
|
||||
};
|
||||
@ -138,20 +218,16 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
if (input.isCoinbase())
|
||||
return;
|
||||
|
||||
if (type === 'pubkey' || type === 'multisig')
|
||||
address = null;
|
||||
|
||||
uaddr = address;
|
||||
|
||||
if (uaddr) {
|
||||
if (!uniq[uaddr])
|
||||
uniq[uaddr] = true;
|
||||
else
|
||||
uaddr = null;
|
||||
if (address && !uniq[address]) {
|
||||
uniq[address] = true;
|
||||
uaddr = address;
|
||||
}
|
||||
|
||||
if (uaddr)
|
||||
batch.del(p + 'p/a/' + uaddr + '/' + hash);
|
||||
if (uaddr) {
|
||||
map[uaddr].forEach(function(id) {
|
||||
batch.del(p + 'p/a/' + id + '/' + hash);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||
@ -159,20 +235,16 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
var address = output.getAddress();
|
||||
var uaddr;
|
||||
|
||||
if (type === 'pubkey' || type === 'multisig')
|
||||
address = null;
|
||||
|
||||
uaddr = address;
|
||||
|
||||
if (uaddr) {
|
||||
if (!uniq[uaddr])
|
||||
uniq[uaddr] = true;
|
||||
else
|
||||
uaddr = null;
|
||||
if (address && !uniq[address]) {
|
||||
uniq[address] = true;
|
||||
uaddr = address;
|
||||
}
|
||||
|
||||
if (uaddr)
|
||||
batch.del(p + 'p/a/' + uaddr + '/' + hash);
|
||||
if (uaddr) {
|
||||
map[uaddr].forEach(function(id) {
|
||||
batch.del(p + 'p/a/' + id + '/' + hash);
|
||||
});
|
||||
}
|
||||
|
||||
self.getCoin(hash, i, function(err, coin) {
|
||||
if (err)
|
||||
@ -210,8 +282,10 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
// Consume unspent money or add orphans
|
||||
utils.forEachSerial(tx.inputs, function(input, next, i) {
|
||||
var key = input.prevout.hash + '/' + input.prevout.index;
|
||||
if (input.isCoinbase())
|
||||
return next();
|
||||
self.getCoin(input.prevout.hash, input.prevout.index, function(err, coin) {
|
||||
var type, address;
|
||||
var type, address, uaddr;
|
||||
|
||||
if (err)
|
||||
return next(err);
|
||||
@ -233,17 +307,26 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
type = input.getType();
|
||||
address = input.getAddress();
|
||||
|
||||
if (type === 'pubkey' || type === 'multisig')
|
||||
address = null;
|
||||
|
||||
if (input.isCoinbase())
|
||||
return next();
|
||||
if (address && !uniq[address]) {
|
||||
uniq[address] = true;
|
||||
uaddr = address;
|
||||
}
|
||||
|
||||
if (address) {
|
||||
batch.del(
|
||||
p + 'u/a/' + address
|
||||
+ '/' + input.prevout.hash
|
||||
+ '/' + input.prevout.index);
|
||||
map[address].forEach(function(id) {
|
||||
batch.del(
|
||||
p + 'u/a/' + id
|
||||
+ '/' + input.prevout.hash
|
||||
+ '/' + input.prevout.index);
|
||||
});
|
||||
}
|
||||
|
||||
if (uaddr) {
|
||||
map[uaddr].forEach(function(id) {
|
||||
batch.put(p + 't/a/' + id + '/' + hash, new Buffer([]));
|
||||
if (tx.ts === 0)
|
||||
batch.put(p + 'p/a/' + id + '/' + hash, new Buffer([]));
|
||||
});
|
||||
}
|
||||
|
||||
batch.del(
|
||||
@ -255,7 +338,7 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
}
|
||||
|
||||
// Only add orphans if this input is ours.
|
||||
self._hasAddress(input.getAddress(), function(err, result) {
|
||||
self.__hasAddress(map, input.getAddress(), function(err, result) {
|
||||
if (err)
|
||||
return done(err);
|
||||
|
||||
@ -308,7 +391,7 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
// Add unspent outputs or resolve orphans
|
||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||
// Do not add unspents for outputs that aren't ours.
|
||||
self._hasAddress(output.getAddress(), function(err, result) {
|
||||
self.__hasAddress(map, output.getAddress(), function(err, result) {
|
||||
var key, coin;
|
||||
|
||||
if (err)
|
||||
@ -382,7 +465,7 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
}
|
||||
|
||||
function finish(err) {
|
||||
var type, adddress;
|
||||
var type, adddress, uaddr;
|
||||
|
||||
if (err)
|
||||
return next(err);
|
||||
@ -391,14 +474,26 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
type = output.getType();
|
||||
address = output.getAddress();
|
||||
|
||||
if (type === 'pubkey' || type === 'multisig')
|
||||
address = null;
|
||||
if (address && !uniq[address]) {
|
||||
uniq[address] = true;
|
||||
uaddr = address;
|
||||
}
|
||||
|
||||
if (address) {
|
||||
batch.put(
|
||||
p + 'u/a/' + address
|
||||
+ '/' + hash + '/' + i,
|
||||
new Buffer([]));
|
||||
map[address].forEach(function(id) {
|
||||
batch.put(
|
||||
p + 'u/a/' + id
|
||||
+ '/' + hash + '/' + i,
|
||||
new Buffer([]));
|
||||
});
|
||||
}
|
||||
|
||||
if (uaddr) {
|
||||
map[uaddr].forEach(function(id) {
|
||||
batch.put(p + 't/a/' + id + '/' + hash, new Buffer([]));
|
||||
if (tx.ts === 0)
|
||||
batch.put(p + 'p/a/' + id + '/' + hash, new Buffer([]));
|
||||
});
|
||||
}
|
||||
|
||||
batch.put(p + 'u/t/' + hash + '/' + i, coin.toRaw());
|
||||
@ -424,23 +519,17 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
else
|
||||
batch.put(p + 't/h/' + tx.height + '/' + hash, new Buffer([]));
|
||||
|
||||
tx.getAddresses().forEach(function(address) {
|
||||
batch.put(p + 't/a/' + address + '/' + hash, new Buffer([]));
|
||||
if (tx.ts === 0)
|
||||
batch.put(p + 'p/a/' + address + '/' + hash, new Buffer([]));
|
||||
});
|
||||
|
||||
batch.write(function(err) {
|
||||
if (err)
|
||||
return done(err);
|
||||
|
||||
self.emit('tx', tx);
|
||||
self.emit('tx', tx, map);
|
||||
|
||||
if (updated) {
|
||||
if (tx.ts !== 0)
|
||||
self.emit('confirmed', tx);
|
||||
self.emit('confirmed', tx, map);
|
||||
|
||||
self.emit('updated', tx);
|
||||
self.emit('updated', tx, map);
|
||||
}
|
||||
|
||||
return done(null, true);
|
||||
@ -452,12 +541,37 @@ TXPool.prototype._add = function add(tx, callback, force) {
|
||||
|
||||
TXPool.prototype.remove = function remove(hash, callback) {
|
||||
var self = this;
|
||||
|
||||
if (Array.isArray(hash)) {
|
||||
return utils.forEachSerial(hash, function(hash, next) {
|
||||
self.remove(hash, next);
|
||||
}, callback);
|
||||
}
|
||||
|
||||
if (hash.hash)
|
||||
hash = hash.hash('hex');
|
||||
|
||||
this.getTX(hash, function(err, tx) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return self._getIDs(tx.getAddresses(), function(err, map) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return self._remove(tx, map, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TXPool.prototype._remove = function remove(hash, map, callback) {
|
||||
var self = this;
|
||||
var p = this.prefix + '/';
|
||||
var uniq = {};
|
||||
|
||||
if (hash.hash)
|
||||
hash = hash.hash('hex');
|
||||
|
||||
// XXX Remove this
|
||||
this.getTX(hash, function(err, tx) {
|
||||
var batch;
|
||||
|
||||
@ -489,29 +603,26 @@ TXPool.prototype.remove = function remove(hash, callback) {
|
||||
if (input.isCoinbase())
|
||||
return;
|
||||
|
||||
if (type === 'pubkey' || type === 'multisig')
|
||||
address = null;
|
||||
|
||||
uaddr = address;
|
||||
|
||||
if (uaddr) {
|
||||
if (!uniq[uaddr])
|
||||
uniq[uaddr] = true;
|
||||
else
|
||||
uaddr = null;
|
||||
if (address && !uniq[address]) {
|
||||
uniq[address] = true;
|
||||
uaddr = address;
|
||||
}
|
||||
|
||||
if (uaddr) {
|
||||
batch.del(p + 't/a/' + uaddr + '/' + hash);
|
||||
if (tx.ts === 0)
|
||||
batch.del(p + 'p/a/' + uaddr + '/' + hash);
|
||||
map[uaddr].forEach(function(id) {
|
||||
batch.del(p + 't/a/' + id + '/' + hash);
|
||||
if (tx.ts === 0)
|
||||
batch.del(p + 'p/a/' + id + '/' + hash);
|
||||
});
|
||||
}
|
||||
|
||||
if (address) {
|
||||
batch.put(p + 'u/a/' + address
|
||||
+ '/' + input.prevout.hash
|
||||
+ '/' + input.prevout.index,
|
||||
new Buffer([]));
|
||||
map[address].forEach(function(id) {
|
||||
batch.put(p + 'u/a/' + id
|
||||
+ '/' + input.prevout.hash
|
||||
+ '/' + input.prevout.index,
|
||||
new Buffer([]));
|
||||
});
|
||||
}
|
||||
|
||||
if (input.output) {
|
||||
@ -529,26 +640,24 @@ TXPool.prototype.remove = function remove(hash, callback) {
|
||||
var address = output.getAddress();
|
||||
var uaddr;
|
||||
|
||||
if (type === 'pubkey' || type === 'multisig')
|
||||
address = null;
|
||||
|
||||
uaddr = address;
|
||||
|
||||
if (uaddr) {
|
||||
if (!uniq[uaddr])
|
||||
uniq[uaddr] = true;
|
||||
else
|
||||
uaddr = null;
|
||||
if (address && !uniq[address]) {
|
||||
uniq[address] = true;
|
||||
uaddr = address;
|
||||
}
|
||||
|
||||
if (uaddr) {
|
||||
batch.del(p + 't/a/' + uaddr + '/' + hash);
|
||||
if (tx.ts === 0)
|
||||
batch.del(p + 'p/a/' + uaddr + '/' + hash);
|
||||
map[uaddr].forEach(function(id) {
|
||||
batch.del(p + 't/a/' + id + '/' + hash);
|
||||
if (tx.ts === 0)
|
||||
batch.del(p + 'p/a/' + id + '/' + hash);
|
||||
});
|
||||
}
|
||||
|
||||
if (address)
|
||||
batch.del(p + 'u/a/' + address + '/' + hash + '/' + i);
|
||||
if (address) {
|
||||
map[address].forEach(function(id) {
|
||||
batch.del(p + 'u/a/' + id + '/' + hash + '/' + i);
|
||||
});
|
||||
}
|
||||
|
||||
batch.del(p + 'u/t/' + hash + '/' + i);
|
||||
});
|
||||
@ -566,12 +675,37 @@ TXPool.prototype.remove = function remove(hash, callback) {
|
||||
|
||||
TXPool.prototype.unconfirm = function unconfirm(hash, callback) {
|
||||
var self = this;
|
||||
|
||||
if (Array.isArray(hash)) {
|
||||
return utils.forEachSerial(hash, function(hash, next) {
|
||||
self.unconfirm(hash, next);
|
||||
}, callback);
|
||||
}
|
||||
|
||||
if (hash.hash)
|
||||
hash = hash.hash('hex');
|
||||
|
||||
this.getTX(hash, function(err, tx) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return self._getIDs(tx.getAddresses(), function(err, map) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return self._unconfirm(tx, map, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TXPool.prototype._unconfirm = function unconfirm(hash, map, callback) {
|
||||
var self = this;
|
||||
var p = this.prefix + '/';
|
||||
var uniq = {};
|
||||
|
||||
if (hash.hash)
|
||||
hash = hash.hash('hex');
|
||||
|
||||
// XXX Remove this.
|
||||
this.getTX(hash, function(err, tx) {
|
||||
var batch, height;
|
||||
|
||||
@ -600,20 +734,16 @@ TXPool.prototype.unconfirm = function unconfirm(hash, callback) {
|
||||
if (input.isCoinbase())
|
||||
return;
|
||||
|
||||
if (type === 'pubkey' || type === 'multisig')
|
||||
address = null;
|
||||
|
||||
uaddr = address;
|
||||
|
||||
if (uaddr) {
|
||||
if (!uniq[uaddr])
|
||||
uniq[uaddr] = true;
|
||||
else
|
||||
uaddr = null;
|
||||
if (address && !uniq[address]) {
|
||||
uniq[address] = true;
|
||||
uaddr = address;
|
||||
}
|
||||
|
||||
if (uaddr)
|
||||
batch.put(p + 'p/a/' + uaddr + '/' + hash, new Buffer([]));
|
||||
if (uaddr) {
|
||||
map[uaddr].forEach(function(id) {
|
||||
batch.put(p + 'p/a/' + id + '/' + hash, new Buffer([]));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||
@ -621,20 +751,16 @@ TXPool.prototype.unconfirm = function unconfirm(hash, callback) {
|
||||
var address = output.getAddress();
|
||||
var uaddr;
|
||||
|
||||
if (type === 'pubkey' || type === 'multisig')
|
||||
address = null;
|
||||
|
||||
uaddr = address;
|
||||
|
||||
if (uaddr) {
|
||||
if (!uniq[uaddr])
|
||||
uniq[uaddr] = true;
|
||||
else
|
||||
uaddr = null;
|
||||
if (address && !uniq[address]) {
|
||||
uniq[address] = true;
|
||||
uaddr = address;
|
||||
}
|
||||
|
||||
if (uaddr)
|
||||
batch.put(p + 'p/a/' + uaddr + '/' + hash, new Buffer([]));
|
||||
if (uaddr) {
|
||||
map[uaddr].forEach(function(id) {
|
||||
batch.put(p + 'p/a/' + id + '/' + hash, new Buffer([]));
|
||||
});
|
||||
}
|
||||
|
||||
self.getCoin(hash, i, function(err, coin) {
|
||||
if (err)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user