use async helpers.

This commit is contained in:
Christopher Jeffrey 2016-02-22 04:25:20 -08:00
parent 86b228ca07
commit 0f4d2ca281
4 changed files with 180 additions and 215 deletions

View File

@ -267,10 +267,8 @@ BlockDB.prototype.saveBlock = function saveBlock(block, callback) {
BlockDB.prototype.removeBlock = function removeBlock(hash, callback) {
var self = this;
callback = utils.once(callback);
this.getBlock(hash, function(err, block) {
var batch, pending;
var batch;
if (err)
return callback(err);
@ -278,8 +276,6 @@ BlockDB.prototype.removeBlock = function removeBlock(hash, callback) {
if (!block)
return callback();
pending = block.txs.length;
batch = self.index.batch();
if (typeof hash === 'string')
@ -288,29 +284,7 @@ BlockDB.prototype.removeBlock = function removeBlock(hash, callback) {
batch.del('b/b/' + block.hash('hex'));
batch.del('b/h/' + block.height);
function done() {
batch.write(function(err) {
if (err)
return callback(err);
// TODO: Add check to make sure we
// can ONLY remove the last block.
assert(block._fileOffset >= 0);
assert(block._fileOffset < self.data.size);
// XXX This seems to be truncating too much right now
return callback(null, block);
self.data.truncateAsync(block._fileOffset, function(err) {
if (err)
return callback(err);
self.emit('remove block', block);
return callback(null, block);
});
});
}
if (!pending)
return done();
block.txs.forEach(function(tx, i) {
utils.forEach(block.txs, function(tx, next, i) {
var hash = tx.hash('hex');
var uniq = {};
@ -321,7 +295,7 @@ BlockDB.prototype.removeBlock = function removeBlock(hash, callback) {
self.fillTX(tx, function(err) {
if (err)
return callback(err);
return next(err);
tx.inputs.forEach(function(input) {
var type = input.getType();
@ -396,8 +370,26 @@ BlockDB.prototype.removeBlock = function removeBlock(hash, callback) {
self.cache.unspent.remove(hash + '/' + i);
});
if (!--pending)
done();
next();
}, function(err) {
if (err)
return callback(err);
batch.write(function(err) {
if (err)
return callback(err);
// TODO: Add check to make sure we
// can ONLY remove the last block.
assert(block._fileOffset >= 0);
assert(block._fileOffset < self.data.size);
// XXX This seems to be truncating too much right now
return callback(null, block);
self.data.truncateAsync(block._fileOffset, function(err) {
if (err)
return callback(err);
self.emit('remove block', block);
return callback(null, block);
});
});
});
});
});
@ -408,62 +400,44 @@ BlockDB.prototype.fillCoins = function fillCoins(txs, callback) {
var pending = txs.length;
callback = utils.asyncify(callback);
callback = utils.once(callback);
if (!pending)
return callback();
txs.forEach(function(tx) {
utils.forEach(txs, function(tx, next) {
self.fillCoin(tx, function(err) {
if (err)
return callback(err);
return next(err);
if (!--pending)
callback();
next();
});
});
}, callback);
};
BlockDB.prototype.fillTXs = function fillTXs(txs, callback) {
var self = this;
var pending = txs.length;
callback = utils.asyncify(callback);
callback = utils.once(callback);
if (!pending)
return callback();
txs.forEach(function(tx) {
utils.forEach(txs, function(err) {
self.fillTX(tx, function(err) {
if (err)
return callback(err);
return next(err);
if (!--pending)
callback();
next();
});
});
}, callback);
};
BlockDB.prototype.fillCoin = function fillCoin(tx, callback) {
var self = this;
var pending = tx.inputs.length;
callback = utils.asyncify(callback);
callback = utils.once(callback);
if (!pending)
return callback();
if (tx.isCoinbase())
return callback();
tx.inputs.forEach(function(input) {
if (input.output) {
if (!--pending)
callback(null, tx);
return;
}
utils.forEach(tx.inputs, function(input, next) {
if (input.output)
return next();
self.getCoin(input.prevout.hash, input.prevout.index, function(err, coin) {
if (err)
return callback(err);
@ -471,71 +445,68 @@ BlockDB.prototype.fillCoin = function fillCoin(tx, callback) {
if (coin)
input.output = coin;
if (!--pending)
callback(null, tx);
next();
});
}, function(err) {
if (err)
return callback(err);
return callback(null, tx);
});
};
BlockDB.prototype.fillTX = function fillTX(tx, callback) {
var self = this;
var pending = tx.inputs.length;
callback = utils.asyncify(callback);
callback = utils.once(callback);
if (!pending)
return callback();
if (tx.isCoinbase())
return callback();
tx.inputs.forEach(function(input) {
if (input.output) {
if (!--pending)
callback(null, tx);
return;
}
utils.forEach(tx.inputs, function(input, next) {
if (input.output)
return next();
self.getTX(input.prevout.hash, function(err, tx) {
if (err)
return callback(err);
return next(err);
if (tx) {
input.output = bcoin.coin(tx, input.prevout.index);
input.output._fileOffset = tx._fileOffset + input.output._offset;
}
if (!--pending)
callback(null, tx);
next();
});
}, function(err) {
if (err)
return callback(err);
return callback(null, tx);
});
};
BlockDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, callback) {
var self = this;
var coins = [];
var pending;
callback = utils.once(callback);
if (typeof addresses === 'string')
addresses = [addresses];
addresses = utils.uniqs(addresses);
pending = addresses.length;
addresses.forEach(function(address) {
utils.forEach(addresses, function(address) {
self._getCoinsByAddress(address, function(err, coin) {
if (err)
return callback(err);
return next(err);
if (coin)
coins = coins.concat(coin);
if (!--pending)
return callback(null, coins);
next();
});
}, function(err) {
if (err)
return callback(err);
return callback(null, coins);
});
};
@ -691,31 +662,26 @@ BlockDB.prototype.getCoin = function getCoin(hash, index, callback) {
BlockDB.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
var self = this;
var txs = [];
var pending;
callback = utils.once(callback);
if (typeof addresses === 'string')
addresses = [addresses];
addresses = utils.uniqs(addresses);
pending = addresses.length;
if (!pending)
return callback(null, txs);
addresses.forEach(function(address) {
utils.forEach(addresses, function(address) {
self._getTXByAddress(address, function(err, tx) {
if (err)
return callback(err);
return next(err);
if (tx)
txs = txs.concat(tx);
if (!--pending)
return callback(null, txs);
next();
});
}, function(err) {
if (err)
return callback(err);
return callback(null, txs);
});
};
@ -966,9 +932,7 @@ BlockDB.prototype.hasCoin = function hasCoin(hash, index, callback) {
BlockDB.prototype.hasUnspentTX = function hasUnspentTX(hash, callback) {
var self = this;
this.getTX(hash, function(err, tx) {
var hash, pending, spent;
callback = utils.once(callback);
var hash, spent;
if (err)
return callback(err);
@ -977,30 +941,23 @@ BlockDB.prototype.hasUnspentTX = function hasUnspentTX(hash, callback) {
return callback(null, false);
hash = tx.hash('hex');
pending = tx.outputs.length;
spent = 0;
if (!pending)
return callback(null, false);
function done(err) {
if (err)
return callback(err);
return callback(null, spent < tx.outputs.length);
}
tx.outputs.forEach(function(output, i) {
utils.forEach(tx.outputs, function(output, next, i) {
self.isSpent(hash, i, function(err, result) {
if (err)
return done(err);
return next(err);
if (result)
spent++;
if (!--pending)
done();
next();
});
});
}, function(err) {
if (err)
return callback(err);
return callback(null, spent < tx.outputs.length);
});
};

View File

@ -571,7 +571,6 @@ Chain.prototype._verify = function _verify(block, prev) {
Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callback) {
var self = this;
var height = prev.height + 1;
var pending = block.txs.length;
if (!this.blockdb || block.subtype !== 'block')
return callback(null, true);
@ -579,18 +578,14 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
if (block.isGenesis())
return callback(null, true);
assert(pending);
callback = utils.once(callback);
// Check all transactions
block.txs.forEach(function(tx) {
utils.every(block.txs, function(tx, next) {
var hash = tx.hash('hex');
// BIP30 - Ensure there are no duplicate txids
self.blockdb.hasTX(hash, function(err, result) {
if (err)
return callback(err);
return next(err);
// Blocks 91842 and 91880 created duplicate
// txids by using the same exact output script
@ -598,13 +593,12 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
if (result) {
utils.debug('Block is overwriting txids: %s', block.rhash);
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
return callback(null, false);
return next(null, false);
}
if (!--pending)
return callback(null, true);
next(null, true);
});
});
}, callback);
};
Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callback) {
@ -1579,14 +1573,12 @@ Chain.prototype.getHashRangeAsync = function getHashRangeAsync(start, end, callb
callback(err, result);
}
done = utils.once(done);
this.byTimeAsync(start, function(err, start) {
if (err)
return done(err);
self.byTimeAsync(end, function(err, end) {
var hashes, i, pending;
var hashes, i;
if (err)
return done(err);
@ -1596,25 +1588,23 @@ Chain.prototype.getHashRangeAsync = function getHashRangeAsync(start, end, callb
if (!start || !end)
return done(null, hashes);
pending = (end.height + 1) - start.height;
for (i = start.height; i < end.height + 1; i++)
getHash(i);
function getHash(i) {
utils.forRange(start.height, end.height + 1, function(i, next) {
self.db.getAsync(i, function(err, entry) {
if (err)
return done(err);
return next(err);
if (!entry)
return done(new Error('No entry for hash range.'));
return next(new Error('No entry for hash range.'));
hashes[i - start.height] = entry.hash;
if (!--pending)
return done(null, hashes);
next();
});
}
}, function(err) {
if (err)
return done(err);
return done(null, hashes);
});
}, true);
}, true);
};
@ -1672,7 +1662,7 @@ Chain.prototype.getLocatorAsync = function getLocatorAsync(start, callback, forc
var hashes = [];
var top = this.height;
var step = 1;
var i, pending;
var i;
var unlock = this._lock(getLocatorAsync, [start, callback], force);
if (!unlock)
@ -1704,15 +1694,6 @@ Chain.prototype.getLocatorAsync = function getLocatorAsync(start, callback, forc
callback = utils.asyncify(callback);
function done(err) {
unlock();
if (err)
return callback(err);
return callback(null, hashes);
}
done = utils.once(done);
i = top;
for (;;) {
hashes.push(i);
@ -1726,26 +1707,25 @@ Chain.prototype.getLocatorAsync = function getLocatorAsync(start, callback, forc
step *= 2;
}
pending = hashes.length;
hashes.forEach(function(height, i) {
if (typeof height === 'string') {
if (!--pending)
done();
return;
}
utils.forEach(hashes, function(height, next, i) {
if (typeof height === 'string')
return next();
self.db.getAsync(height, function(err, existing) {
if (err)
return done(err);
return next(err);
assert(existing);
hashes[i] = existing.hash;
if (!--pending)
done();
next();
});
}, function(err) {
unlock();
if (err)
return callback(err);
return callback(null, hashes);
});
};

View File

@ -510,7 +510,7 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback,
var osize = this.size;
var ohighest = this.highest;
var otip = this.tip;
var size, count, pending, called;
var size, count;
callback = utils.asyncify(callback);
@ -522,7 +522,6 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback,
size = (height + 1) * BLOCK_SIZE;
count = this.getSize();
pending = count - (height + 1);
if (height > count - 1)
return callback(new Error('Height too high'));
@ -544,13 +543,23 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback,
self.height = self.tip.height;
self.emit('tip', self.tip);
for (i = height + 1; i < count; i++)
dropEntry(i);
function finish(err) {
if (err) {
self.size = osize;
self.highest = ohighest;
self.tip = otip;
self.height = self.tip.height;
self.emit('tip', self.tip);
return callback(err);
}
function dropEntry(i) {
callback();
}
utils.forRange(height + 1, count, function(i, next) {
self.getAsync(i, function(err, existing) {
if (err)
return done(err);
return next(err);
assert(existing);
@ -566,17 +575,9 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback,
delete self.cache[i];
delete self.heightLookup[existing.hash];
if (!--pending)
done();
return next();
}, true);
}
function done(err) {
if (called)
return;
called = true;
}, function(err) {
if (err)
return finish(err);
@ -593,20 +594,7 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback,
return finish();
});
});
}
function finish(err) {
if (err) {
self.size = osize;
self.highest = ohighest;
self.tip = otip;
self.height = self.tip.height;
self.emit('tip', self.tip);
return callback(err);
}
callback();
}
});
});
};

View File

@ -1475,7 +1475,7 @@ utils.ccmp = function(a, b) {
utils.forRange = function forRange(from, to, iter, callback) {
var pending = to - from;
var called, i;
var i, error;
callback = utils.asyncify(callback);
@ -1483,16 +1483,10 @@ utils.forRange = function forRange(from, to, iter, callback) {
return callback();
function next(err) {
if (called)
return;
if (err) {
called = true;
return callback(err);
}
if (!--pending) {
called = true;
callback();
}
if (err)
error = err;
if (!--pending)
callback(error);
}
for (i = from; i < to; i++)
@ -1501,7 +1495,7 @@ utils.forRange = function forRange(from, to, iter, callback) {
utils.forEach = function forEach(arr, iter, callback) {
var pending = arr.length;
var called, i;
var i, error;
callback = utils.asyncify(callback);
@ -1509,16 +1503,10 @@ utils.forEach = function forEach(arr, iter, callback) {
return callback();
function next(err) {
if (called)
return;
if (err) {
called = true;
return callback(err);
}
if (!--pending) {
called = true;
callback();
}
if (err)
error = err;
if (!--pending)
callback(error);
}
arr.forEach(function(item, i) {
@ -1535,7 +1523,9 @@ utils.forRangeSerial = function forRangeSerial(from, to, iter, callback) {
if (from >= to)
return callback();
from++;
iter(from - 1, next, from - 1);
utils.nextTick(function() {
iter(from - 1, next, from - 1);
});
})();
};
@ -1552,7 +1542,57 @@ utils.forEachSerial = function forEachSerial(arr, iter, callback) {
return callback();
item = arr[i];
i++;
iter(item, next, i - 1);
utils.nextTick(function() {
iter(item, next, i - 1);
});
})();
};
utils.every = function every(arr, iter, callback) {
var pending = arr.length;
var result = true;
var i, error;
callback = utils.asyncify(callback);
if (!pending)
return callback(null, result);
function next(err, res) {
if (err)
error = err;
if (!res)
result = false;
if (!--pending) {
if (error)
return callback(error);
callback(null, result);
}
}
arr.forEach(function(item, i) {
iter(item, next, i);
});
};
utils.everySerial = function everySerial(arr, iter, callback) {
var i = 0;
callback = utils.asyncify(callback);
(function next(err, res) {
var item;
if (err)
return callback(err);
if (!result)
return callback(null, false);
if (i >= arr.length)
return callback(null, true);
item = arr[i];
i++;
utils.nextTick(function() {
iter(item, next, i - 1);
});
})();
};