refactor.

This commit is contained in:
Christopher Jeffrey 2016-04-16 05:55:00 -07:00
parent 0d75c8a621
commit 0d7d8073a2
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
8 changed files with 163 additions and 147 deletions

View File

@ -347,7 +347,7 @@ Chain.prototype._preload = function _preload(callback) {
stream.on('data', function(data) {
var blocks = [];
var need = 80 - buf.size;
var lastEntry;
var lastEntry, block, entry, start;
while (data.length >= need) {
buf.data.push(data.slice(0, need));
@ -367,8 +367,8 @@ Chain.prototype._preload = function _preload(callback) {
if (blocks.length === 0)
return;
blocks.forEach(function(data) {
var block, entry, start;
for (i = 0; i < blocks.length; i++) {
block = blocks[i];
try {
data = parseHeader(data);
@ -423,7 +423,7 @@ Chain.prototype._preload = function _preload(callback) {
lastEntry = entry;
height++;
});
}
});
stream.on('end', function() {

View File

@ -19,9 +19,13 @@ var DUMMY = new Buffer([0]);
* @exports ChainDB
* @constructor
* @param {Object} options
* @param {Boolean?} options.prune
* @param {Boolean?} options.spv
* @param {Number?} options.keepBlocks
* @param {Boolean?} options.prune - Whether to prune the chain.
* @param {Boolean?} options.spv - SPV-mode, will not save block
* data, only entries.
* @param {Number?} [options.keepBlocks=288] - Number of
* blocks to keep when pruning.
* @param {Boolean?} options.paranoid - Perform some paranoid checks
* against hashes. Will throw if corruption is detected.
* @param {String?} options.name - Database name
* @param {String?} options.location - Database location
* @param {String?} options.db - Database backend name
@ -165,8 +169,8 @@ ChainDB.prototype.addCache = function addCache(entry) {
};
/**
* Test the cache for a present transaction.
* @param {Hash} hash
* Test the cache for a present entry hash or height.
* @param {Hash|Number} hash - Hash or height.
*/
ChainDB.prototype.hasCache = function hasCache(hash) {
@ -180,10 +184,10 @@ ChainDB.prototype.hasCache = function hasCache(hash) {
};
/**
* Get a transaction directly from the LRU cache. This is
* Get an entry directly from the LRU cache. This is
* useful for optimization if we don't want to wait on a
* nextTick during a `get()` call.
* @param {Hash} hash
* @param {Hash|Number} hash - Hash or height.
*/
ChainDB.prototype.getCache = function getCache(hash) {
@ -718,14 +722,17 @@ ChainDB.prototype.has = function has(height, callback) {
*/
ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback) {
var i, tx;
if (this.options.spv)
return utils.nextTick(callback);
batch.put('b/b/' + block.hash('hex'), block.toCompact());
block.txs.forEach(function(tx) {
for (i = 0; i < block.txs.length; i++) {
tx = block.txs[i];
batch.put('t/t/' + tx.hash('hex'), tx.toExtended());
});
}
if (!connect)
return utils.nextTick(callback);
@ -743,6 +750,7 @@ ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback
ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
var self = this;
var i, tx;
if (this.options.spv)
return utils.nextTick(callback);
@ -756,9 +764,10 @@ ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
batch.del('b/b/' + block.hash('hex'));
block.txs.forEach(function(tx) {
for (i = 0; i < block.txs.length; i++) {
tx = block.txs[i];
batch.del('t/t/' + tx.hash('hex'));
});
}
self.disconnectBlock(block, batch, callback);
});
@ -773,6 +782,7 @@ ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
var self = this;
var i, j, tx, input, output, key, address, hash, uniq;
if (this.options.spv) {
self.emit('add block', block);
@ -788,16 +798,17 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
if (!block)
return callback();
block.txs.forEach(function(tx) {
var hash = tx.hash('hex');
var uniq = {};
for (i = 0; i < block.txs.length; i++) {
tx = block.txs[i];
hash = tx.hash('hex');
uniq = {};
tx.inputs.forEach(function(input) {
var key = input.prevout.hash + '/' + input.prevout.index;
var address;
for (j = 0; j < tx.inputs.length; j++) {
input = tx.inputs[j];
key = input.prevout.hash + '/' + input.prevout.index;
if (tx.isCoinbase())
return;
break;
assert(input.coin);
@ -814,11 +825,11 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
}
batch.del('u/t/' + key);
});
}
tx.outputs.forEach(function(output, i) {
var key = hash + '/' + i;
var address;
for (j = 0; j < tx.inputs.length; j++) {
output = tx.outputs[j];
key = hash + '/' + j;
if (self.options.indexAddress) {
address = output.getAddress();
@ -832,9 +843,9 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
batch.put('u/a/' + address + '/' + key, DUMMY);
}
batch.put('u/t/' + key, bcoin.coin(tx, i).toRaw());
});
});
batch.put('u/t/' + key, bcoin.coin(tx, j).toRaw());
}
}
self.emit('add block', block);
@ -849,13 +860,14 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
* @param {Function} callback - Returns [Error, {@link Block}].
*/
ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callback) {
ChainDB.prototype.disconnectBlock = function disconnectBlock(block, batch, callback) {
var self = this;
var i, j, tx, input, output, key, address, hash, uniq;
if (this.options.spv)
return utils.nextTick(callback);
this._ensureHistory(hash, function(err, block) {
this._ensureHistory(block, function(err, block) {
if (err)
return callback(err);
@ -863,20 +875,21 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
return callback(new Error('Block not found.'));
if (self.options.paranoid) {
if (typeof hash === 'string')
assert(block.hash('hex') === hash, 'Database is corrupt.');
if (typeof block === 'string')
assert(block.hash('hex') === block, 'Database is corrupt.');
}
block.txs.slice().reverse().forEach(function(tx) {
var hash = tx.hash('hex');
var uniq = {};
for (i = block.txs.length - 1; i >= 0; i--) {
tx = block.txs[i];
hash = tx.hash('hex');
uniq = {};
tx.inputs.forEach(function(input) {
var key = input.prevout.hash + '/' + input.prevout.index;
var address;
for (j = 0; j < tx.inputs.length; j++) {
input = tx.inputs[j];
key = input.prevout.hash + '/' + input.prevout.index;
if (tx.isCoinbase())
return;
break;
assert(input.coin);
@ -893,11 +906,11 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
}
batch.put('u/t/' + key, input.coin.toRaw());
});
}
tx.outputs.forEach(function(output, i) {
var key = hash + '/' + i;
var address;
for (j = 0; j < tx.inputs.length; j++) {
output = tx.outputs[j];
key = hash + '/' + j;
if (self.options.indexAddress) {
address = output.getAddress();
@ -912,8 +925,8 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
}
batch.del('u/t/' + key);
});
});
}
}
self.emit('remove block', block);
@ -1032,16 +1045,11 @@ ChainDB.prototype.fillTX = function fillTX(tx, callback) {
* @param {Function} callback - Returns [Error, {@link Coin}[]].
*/
ChainDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, options, callback) {
ChainDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, callback) {
var self = this;
var ids = [];
var coins = [];
if (!callback) {
callback = options;
options = {};
}
if (typeof addresses === 'string')
addresses = [addresses];
@ -1141,17 +1149,12 @@ ChainDB.prototype.getCoin = function getCoin(hash, index, callback) {
* @param {Function} callback - Returns [Error, {@link TX}[]].
*/
ChainDB.prototype.getTXByAddress = function getTXByAddress(addresses, options, callback) {
ChainDB.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
var self = this;
var hashes = [];
var txs = [];
var have = {};
if (!callback) {
callback = options;
options = {};
}
if (typeof addresses === 'string')
addresses = [addresses];
@ -1543,6 +1546,7 @@ ChainDB.prototype.isSpentTX = function isSpentTX(hash, callback) {
ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
var futureHeight;
var i, j, tx, input;
if (this.options.spv)
return callback();
@ -1558,11 +1562,15 @@ ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
batch.put('b/q/' + futureHeight, block.hash());
block.txs.forEach(function(tx) {
if (tx.isCoinbase())
return;
for (i = 0; i < block.txs.length; i++) {
tx = block.txs[i];
if (tx.isCoinbase())
break;
for (j = 0; j < tx.inputs.length; j++) {
input = tx.inputs[j];
tx.inputs.forEach(function(input) {
assert(input.coin);
batch.put('u/x/'
@ -1575,8 +1583,8 @@ ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
+ '/' + input.prevout.hash
+ '/' + input.prevout.index,
DUMMY);
});
});
}
}
this._pruneQueue(block, batch, callback);
};
@ -1584,6 +1592,8 @@ ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
ChainDB.prototype._pruneQueue = function _pruneQueue(block, batch, callback) {
var self = this;
var key = 'b/q/' + pad32(block.height);
var i;
this.db.get(key, function(err, hash) {
if (err && err.type !== 'NotFoundError')
return callback(err);
@ -1610,9 +1620,8 @@ ChainDB.prototype._pruneQueue = function _pruneQueue(block, batch, callback) {
batch.del('b/b/' + hash);
compact.hashes.forEach(function(hash) {
batch.del('t/t/' + hash);
});
for (i = 0; i < compact.hashes.length; i++)
batch.del('t/t/' + compact.hashes[i]);
self._pruneCoinQueue(block, batch, callback);
});

View File

@ -150,9 +150,16 @@ CoinView.prototype.fill = function fill(obj, spend) {
*/
CoinView.prototype.toArray = function toArray() {
return Object.keys(this.coins).map(function(hash) {
return this.coins[hash];
}, this);
var keys = Object.keys(this.coins);
var out = [];
var i, hash;
for (i = 0; i < keys.length; i++) {
hash = keys[i];
out = out.concat(this.coins[hash].toArray());
}
return out;
};
return CoinView;

View File

@ -14,7 +14,7 @@ var assert = utils.assert;
var request = require('./request');
/**
* Client
* BCoin HTTP client.
* @exports Client
* @constructor
* @param {String} uri

View File

@ -1145,9 +1145,9 @@ Mempool.prototype.removeOrphan = function removeOrphan(tx, callback) {
}
p = new BufferWriter();
hashes.forEach(function(hash) {
p.writeHash(hash);
});
for (i = 0; i < hashes.length; i++)
p.writeHash(hashes[i]);
batch.put('m/d/' + prev, p.render());
@ -1410,7 +1410,7 @@ Mempool.prototype._addUnchecked = function addUnchecked(tx, callback, force) {
var self = this;
var prefix = 'm/';
var hash = tx.hash('hex');
var batch;
var i, addresses, address, input, output, key, coin, batch;
var unlock = this.writeLock.lock(addUnchecked, [tx, callback], force);
if (!unlock)
@ -1423,18 +1423,20 @@ Mempool.prototype._addUnchecked = function addUnchecked(tx, callback, force) {
batch.put(prefix + 't/t/' + hash, tx.toExtended());
batch.put(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash, DUMMY);
tx.getAddresses().forEach(function(address) {
batch.put(prefix + 't/a/' + address + '/' + hash, DUMMY);
});
addresses = tx.getAddresses();
tx.inputs.forEach(function(input) {
var key = input.prevout.hash + '/' + input.prevout.index;
var address;
for (i = 0; i < addresses.length; i++)
batch.put(prefix + 't/a/' + addresses[i] + '/' + hash, DUMMY);
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
key = input.prevout.hash + '/' + input.prevout.index;
if (tx.isCoinbase())
return;
break;
assert(input.coin);
address = input.getAddress();
batch.del(prefix + 'u/t/' + key);
@ -1442,18 +1444,19 @@ Mempool.prototype._addUnchecked = function addUnchecked(tx, callback, force) {
if (address)
batch.del(prefix + 'u/a/' + address + '/' + key);
});
}
tx.outputs.forEach(function(output, i) {
var key = hash + '/' + i;
var address = output.getAddress();
var coin = bcoin.coin(tx, i).toRaw();
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
key = hash + '/' + i;
address = output.getAddress();
coin = bcoin.coin(tx, i).toRaw();
batch.put(prefix + 'u/t/' + key, coin);
if (address)
batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY);
});
}
return batch.write(callback);
};
@ -1469,7 +1472,7 @@ Mempool.prototype._addUnchecked = function addUnchecked(tx, callback, force) {
Mempool.prototype._removeUnchecked = function removeUnchecked(hash, callback, force) {
var self = this;
var prefix = 'm/';
var batch;
var batch, i, addresses, output;
var unlock = this.writeLock.lock(removeUnchecked, [hash, callback], force);
if (!unlock)
@ -1492,9 +1495,10 @@ Mempool.prototype._removeUnchecked = function removeUnchecked(hash, callback, fo
batch.del(prefix + 't/t/' + hash);
batch.del(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash);
tx.getAddresses().forEach(function(address) {
batch.del(prefix + 't/a/' + address + '/' + hash);
});
addresses = tx.getAddresses();
for (i = 0; i < addresses.length; i++)
batch.del(prefix + 't/a/' + addresses[i] + '/' + hash);
utils.forEachSerial(tx.inputs, function(input, next) {
var key = input.prevout.hash + '/' + input.prevout.index;
@ -1530,15 +1534,16 @@ Mempool.prototype._removeUnchecked = function removeUnchecked(hash, callback, fo
if (err)
return callback(err);
tx.outputs.forEach(function(output, i) {
var key = hash + '/' + i;
var address = output.getAddress();
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
key = hash + '/' + i;
address = output.getAddress();
batch.del(prefix + 'u/t/' + key);
if (address)
batch.del(prefix + 'u/a/' + address + '/' + key);
});
}
return batch.write(callback);
});

View File

@ -1070,7 +1070,7 @@ Peer.prototype._handleGetData = function handleGetData(items) {
var isWitness = item.type & constants.invWitnessMask;
var type = item.type & ~constants.invWitnessMask;
var hash = utils.toHex(item.hash);
var data;
var i, tx, data;
if (type === constants.inv.tx) {
if (!self.mempool) {
@ -1156,14 +1156,16 @@ Peer.prototype._handleGetData = function handleGetData(items) {
self._write(self.framer.merkleBlock(block));
block.txs.forEach(function(tx) {
for (i = 0; i < block.txs.length; i++) {
tx = block.txs[i];
if (isWitness)
tx = tx.renderWitness();
else
tx = tx.renderNormal();
self._write(self.framer.packet('tx', tx));
});
}
if (hash === self.hashContinue) {
self._write(self.framer.inv([{

View File

@ -32,7 +32,6 @@ var constants = bcoin.protocol.constants;
* send another getblocks request.
* @param {Number?} [requestTimeout=120000] - Timeout for in-flight blocks.
* @param {Number?} [invTimeout=60000] - Timeout for broadcasted objects.
* @param {Wallet[]?} wallets - Wallets to add to the bloom filter.
* @param {Boolean?} listen - Whether to spin up a server socket
* and listen for peers.
* @param {Boolean?} selfish - A selfish pool. Will not serve blocks,
@ -293,10 +292,6 @@ Pool.prototype._init = function _init() {
self.emit('full');
bcoin.debug('Chain is fully synced (height=%d).', self.chain.height);
});
(this.options.wallets || []).forEach(function(wallet) {
self.addWallet(wallet);
});
};
/**
@ -893,12 +888,13 @@ Pool.prototype._load = function _load() {
*/
Pool.prototype.getMempool = function getMempool() {
var i;
if (this.peers.load)
this.peers.load.getMempool();
this.peers.regular.forEach(function(peer) {
peer.getMempool();
});
for (i = 0; i < this.peers.regular.length; i++)
this.peers.regular[i].getMempool();
};
Pool.prototype._createPeer = function _createPeer(options) {
@ -943,11 +939,14 @@ Pool.prototype._createPeer = function _createPeer(options) {
});
peer.on('notfound', function(items) {
items.forEach(function(item) {
var req = self.request.map[utils.toHex(item.hash)];
var i, item;
for (i = 0; i < items.length; i++) {
item = items[i];
req = self.request.map[utils.toHex(item.hash)];
if (req && req.peer === peer)
item.finish();
});
}
});
peer.on('tx', function(tx) {
@ -979,6 +978,8 @@ Pool.prototype._createPeer = function _createPeer(options) {
});
peer.on('txs', function(txs) {
var i, hash;
self.emit('txs', txs, peer);
if (!self.options.spv) {
@ -986,11 +987,11 @@ Pool.prototype._createPeer = function _createPeer(options) {
return;
}
txs.forEach(function(hash) {
hash = utils.toHex(hash);
for (i = 0; i < txs.length; i++) {
hash = utils.toHex(txs[i]);
if (self.markTX(hash, 0))
self.getData(peer, self.tx.type, hash);
});
}
});
peer.on('version', function(version) {
@ -1356,6 +1357,7 @@ Pool.prototype.updateWatch = function updateWatch() {
Pool.prototype.addWallet = function addWallet(wallet, callback) {
var self = this;
var i;
callback = utils.asyncify(callback);
@ -1366,9 +1368,8 @@ Pool.prototype.addWallet = function addWallet(wallet, callback) {
if (err)
return callback(err);
txs.forEach(function(tx) {
self.sendTX(tx);
});
for (i = 0; i < txs.length; i++)
self.sendTX(txs[i]);
if (!self.options.spv)
return callback();
@ -1713,7 +1714,7 @@ Pool.prototype._sendRequests = function _sendRequests(peer) {
*/
Pool.prototype.fulfill = function fulfill(hash) {
var item;
var i, item;
if (Buffer.isBuffer(hash))
hash = utils.toHex(hash);
@ -1726,9 +1727,8 @@ Pool.prototype.fulfill = function fulfill(hash) {
item.finish();
item.callback.forEach(function(callback) {
callback();
});
for (i = 0; i < item.callback.length; i++)
item.callback[i]();
return item;
};
@ -1811,10 +1811,12 @@ Pool.prototype.getTX = function getTX(hash, range, callback) {
range = { start: utils.now() - delta, end: 0 };
function done(err, tx, range) {
var i;
delete self.validate.map[hash];
cbs.forEach(function(callback) {
callback(err, tx, range);
});
for (i = 0; i < cbs.length; i++)
cbs[i](err, tx, range);
}
(function next() {
@ -2093,11 +2095,13 @@ Pool.prototype._getRandom = function _getRandom(seeds, uniq) {
*/
Pool.prototype.setSeeds = function setSeeds(seeds) {
var i, seed;
this.seeds = [];
this.hosts = {};
seeds.forEach(function(seed) {
this.addSeed(seed);
}, this);
for (i = 0; i < seeds.length; i++)
this.addSeed(seeds[i]);
};
/**

View File

@ -547,14 +547,11 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
if (!orphans) {
if (self.options.indexAddress && address) {
map.table[address].forEach(function(id) {
batch.put(
prefix + 'u/a/' + id
+ '/' + hash + '/' + i,
DUMMY);
batch.put(prefix + 'u/a/' + id + '/' + key, DUMMY);
});
}
batch.put(prefix + 'u/t/' + hash + '/' + i, coin.toRaw());
batch.put(prefix + 'u/t/' + key, coin.toRaw());
updated = true;
}
@ -905,6 +902,7 @@ TXPool.prototype._remove = function remove(tx, map, callback, force) {
return callback(err);
tx.inputs.forEach(function(input) {
var key = input.prevout.hash + '/' + input.prevout.index;
var address = input.getAddress();
if (tx.isCoinbase())
@ -920,26 +918,17 @@ TXPool.prototype._remove = function remove(tx, map, callback, force) {
if (self.options.indexAddress && address) {
map.table[address].forEach(function(id) {
batch.put(prefix + 'u/a/' + id
+ '/' + input.prevout.hash
+ '/' + input.prevout.index,
DUMMY);
batch.put(prefix + 'u/a/' + id + '/' + key, DUMMY);
});
}
batch.put(prefix + 'u/t/'
+ input.prevout.hash
+ '/' + input.prevout.index,
input.coin.toRaw());
batch.del(prefix + 's/t/'
+ input.prevout.hash
+ '/' + input.prevout.index);
batch.del(prefix + 'o/' + input.prevout.hash + '/' + input.prevout.index);
batch.put(prefix + 'u/t/' + key, input.coin.toRaw());
batch.del(prefix + 's/t/' + key);
batch.del(prefix + 'o/' + key);
});
tx.outputs.forEach(function(output, i) {
var key = hash + '/' + i;
var address = output.getAddress();
if (self.options.mapAddress) {
@ -949,11 +938,11 @@ TXPool.prototype._remove = function remove(tx, map, callback, force) {
if (self.options.indexAddress && address) {
map.table[address].forEach(function(id) {
batch.del(prefix + 'u/a/' + id + '/' + hash + '/' + i);
batch.del(prefix + 'u/a/' + id + '/' + key);
});
}
batch.del(prefix + 'u/t/' + hash + '/' + i);
batch.del(prefix + 'u/t/' + key);
});
batch.write(function(err) {