use async helpers.
This commit is contained in:
parent
86b228ca07
commit
0f4d2ca281
@ -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);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
});
|
||||
})();
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user