chaindb.
This commit is contained in:
parent
2c861aff82
commit
8f85f0b5c9
@ -16,11 +16,11 @@ var pad32 = utils.pad32;
|
|||||||
* BlockDB
|
* BlockDB
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function BlockDB(node, options) {
|
function BlockDB(options, db) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (!(this instanceof BlockDB))
|
if (!(this instanceof BlockDB))
|
||||||
return new BlockDB(node, options);
|
return new BlockDB(options);
|
||||||
|
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
@ -32,12 +32,7 @@ function BlockDB(node, options) {
|
|||||||
this.keepBlocks = options.keepBlocks || 288;
|
this.keepBlocks = options.keepBlocks || 288;
|
||||||
this.prune = !!options.prune;
|
this.prune = !!options.prune;
|
||||||
|
|
||||||
this.node = node;
|
this.db = db;
|
||||||
|
|
||||||
this.db = bcoin.ldb('block', {
|
|
||||||
cacheSize: 16 * 1024 * 1024,
|
|
||||||
writeBufferSize: 8 * 1024 * 1024
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.inherits(BlockDB, EventEmitter);
|
utils.inherits(BlockDB, EventEmitter);
|
||||||
@ -52,9 +47,8 @@ BlockDB.prototype.close = function close(callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDB.prototype.saveBlock = function saveBlock(block, callback) {
|
BlockDB.prototype.saveBlock = function saveBlock(block, batch, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var batch = this.batch();
|
|
||||||
|
|
||||||
batch.put('b/b/' + block.hash('hex'), block.toCompact());
|
batch.put('b/b/' + block.hash('hex'), block.toCompact());
|
||||||
|
|
||||||
@ -62,7 +56,9 @@ BlockDB.prototype.saveBlock = function saveBlock(block, callback) {
|
|||||||
batch.put('t/t/' + tx.hash('hex'), tx.toExtended());
|
batch.put('t/t/' + tx.hash('hex'), tx.toExtended());
|
||||||
});
|
});
|
||||||
|
|
||||||
self.connectBlock(block, function(err) {
|
self.connectBlock(block, batch, callback);
|
||||||
|
return;
|
||||||
|
self.connectBlock(block, batch, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -72,40 +68,36 @@ BlockDB.prototype.saveBlock = function saveBlock(block, callback) {
|
|||||||
// Check for now-fully-spent txs. Try to remove
|
// Check for now-fully-spent txs. Try to remove
|
||||||
// them or queue them up for future deletion if
|
// them or queue them up for future deletion if
|
||||||
// it is currently unsafe to remove them.
|
// it is currently unsafe to remove them.
|
||||||
self._pruneBlock(block, function(err) {
|
self._pruneBlock(block, batch, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
return callback(null, block);
|
return callback(null, block);
|
||||||
});
|
});
|
||||||
}, batch);
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDB.prototype.removeBlock = function removeBlock(hash, callback) {
|
BlockDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._getTXBlock(hash, function(err, block) {
|
this._getTXBlock(hash, function(err, block) {
|
||||||
var batch;
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!block)
|
if (!block)
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
batch = self.batch();
|
|
||||||
|
|
||||||
batch.del('b/b/' + block.hash('hex'));
|
batch.del('b/b/' + block.hash('hex'));
|
||||||
|
|
||||||
block.txs.forEach(function(tx, i) {
|
block.txs.forEach(function(tx, i) {
|
||||||
batch.del('t/t/' + tx.hash('hex'));
|
batch.del('t/t/' + tx.hash('hex'));
|
||||||
});
|
});
|
||||||
|
|
||||||
self.disconnectBlock(block, callback, batch);
|
self.disconnectBlock(block, batch, callback);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDB.prototype.connectBlock = function connectBlock(block, callback, batch) {
|
BlockDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._getCoinBlock(block, function(err, block) {
|
this._getCoinBlock(block, function(err, block) {
|
||||||
@ -114,19 +106,8 @@ BlockDB.prototype.connectBlock = function connectBlock(block, callback, batch) {
|
|||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!block) {
|
if (!block)
|
||||||
assert(!batch);
|
|
||||||
return callback();
|
return callback();
|
||||||
}
|
|
||||||
|
|
||||||
if (!batch)
|
|
||||||
batch = self.batch();
|
|
||||||
|
|
||||||
batch.put('b/h/' + pad32(block.height), block.hash());
|
|
||||||
|
|
||||||
height = new Buffer(4);
|
|
||||||
utils.writeU32(height, block.height, 0);
|
|
||||||
batch.put('b/t', height);
|
|
||||||
|
|
||||||
block.txs.forEach(function(tx, i) {
|
block.txs.forEach(function(tx, i) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
@ -178,40 +159,25 @@ BlockDB.prototype.connectBlock = function connectBlock(block, callback, batch) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
batch.write(function(err) {
|
self.emit('add block', block);
|
||||||
if (err)
|
|
||||||
return callback(err);
|
return callback(null, block);
|
||||||
self.emit('save block', block);
|
|
||||||
return callback(null, block);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDB.prototype.disconnectBlock = function disconnectBlock(hash, callback, batch) {
|
BlockDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._getTXBlock(hash, function(err, block) {
|
this._getTXBlock(hash, function(err, block) {
|
||||||
var height;
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!block) {
|
if (!block)
|
||||||
assert(!batch);
|
|
||||||
return callback();
|
return callback();
|
||||||
}
|
|
||||||
|
|
||||||
if (!batch)
|
|
||||||
batch = self.batch();
|
|
||||||
|
|
||||||
if (typeof hash === 'string')
|
if (typeof hash === 'string')
|
||||||
assert(block.hash('hex') === hash);
|
assert(block.hash('hex') === hash);
|
||||||
|
|
||||||
height = new Buffer(4);
|
|
||||||
utils.writeU32(height, block.height - 1, 0);
|
|
||||||
batch.put('b/t', height);
|
|
||||||
batch.del('b/h/' + pad32(block.height));
|
|
||||||
|
|
||||||
block.txs.forEach(function(tx, i) {
|
block.txs.forEach(function(tx, i) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
var uniq = {};
|
var uniq = {};
|
||||||
@ -265,12 +231,8 @@ BlockDB.prototype.disconnectBlock = function disconnectBlock(hash, callback, bat
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
batch.write(function(err) {
|
self.emit('remove block', block);
|
||||||
if (err)
|
return callback(null, block);
|
||||||
return callback(err);
|
|
||||||
self.emit('remove block', block);
|
|
||||||
return callback(null, block);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -692,7 +654,7 @@ BlockDB.prototype._getHash = function _getHash(height, callback) {
|
|||||||
if (typeof height === 'string')
|
if (typeof height === 'string')
|
||||||
return callback(null, height);
|
return callback(null, height);
|
||||||
|
|
||||||
this.db.get('b/h/' + pad32(height), function(err, hash) {
|
this.db.get('c/h/' + pad32(height), function(err, hash) {
|
||||||
if (err && err.type !== 'NotFoundError')
|
if (err && err.type !== 'NotFoundError')
|
||||||
return callback(err);
|
return callback(err);
|
||||||
if (!hash)
|
if (!hash)
|
||||||
@ -806,6 +768,10 @@ BlockDB.prototype.isUnspentTX = function isUnspentTX(hash, callback) {
|
|||||||
BlockDB.prototype.isSpentTX = function isSpentTX(hash, callback) {
|
BlockDB.prototype.isSpentTX = function isSpentTX(hash, callback) {
|
||||||
var spent = true;
|
var spent = true;
|
||||||
|
|
||||||
|
// Important!
|
||||||
|
if (hash.hash)
|
||||||
|
hash = hash.hash('hex');
|
||||||
|
|
||||||
var iter = this.db.db.iterator({
|
var iter = this.db.db.iterator({
|
||||||
gte: 'u/t/' + hash,
|
gte: 'u/t/' + hash,
|
||||||
lte: 'u/t/' + hash + '~',
|
lte: 'u/t/' + hash + '~',
|
||||||
@ -828,7 +794,8 @@ BlockDB.prototype.isSpentTX = function isSpentTX(hash, callback) {
|
|||||||
|
|
||||||
spent = false;
|
spent = false;
|
||||||
|
|
||||||
next();
|
// IMPORTANT!
|
||||||
|
iter.end(done);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@ -864,72 +831,9 @@ BlockDB.prototype.isSpent = function isSpent(hash, index, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDB.prototype.getHeight = function getHeight(callback) {
|
BlockDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
return this.db.get('b/t', function(err, height) {
|
|
||||||
if (err && err.type !== 'NotFoundError')
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (!height)
|
|
||||||
return callback(null, -1);
|
|
||||||
|
|
||||||
return callback(null, utils.readU32(height, 0));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
BlockDB.prototype.getTipHash = function getTipHash(callback) {
|
|
||||||
return this.getHeight(function(err, height) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (height === -1)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
return self.db.get('b/h/' + pad32(height), function(err, hash) {
|
|
||||||
if (err && err.type !== 'NotFoundError')
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (!hash)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
return callback(null, utils.toHex(hash));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
BlockDB.prototype.reset = function reset(height, callback, emit) {
|
|
||||||
var self = this;
|
|
||||||
this.getHeight(function(err, currentHeight) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (currentHeight < height)
|
|
||||||
return callback(new Error('Cannot reset to height ' + height));
|
|
||||||
|
|
||||||
(function next() {
|
|
||||||
if (currentHeight === height)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
self.removeBlock(currentHeight, function(err, block) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
// Emit the blocks we removed.
|
|
||||||
if (emit && block)
|
|
||||||
emit(block);
|
|
||||||
|
|
||||||
currentHeight--;
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
BlockDB.prototype._pruneBlock = function _pruneBlock(block, callback) {
|
|
||||||
var self = this;
|
|
||||||
var batch = this.batch();
|
|
||||||
|
|
||||||
// For much more aggressive pruning, we could delete
|
// For much more aggressive pruning, we could delete
|
||||||
// the block headers 288 blocks before this one here as well.
|
// the block headers 288 blocks before this one here as well.
|
||||||
|
|
||||||
@ -942,7 +846,7 @@ BlockDB.prototype._pruneBlock = function _pruneBlock(block, callback) {
|
|||||||
self._pruneQueue(block, batch, function(err) {
|
self._pruneQueue(block, batch, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
return batch.write(callback);
|
return callback();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -34,8 +34,7 @@ function Chain(node, options) {
|
|||||||
this.node = node;
|
this.node = node;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.mempool = node.mempool;
|
this.mempool = node.mempool;
|
||||||
this.blockdb = node.blockdb;
|
this.db = new bcoin.chaindb(this, options);
|
||||||
this.db = new bcoin.chaindb(node, this, options);
|
|
||||||
this.busy = false;
|
this.busy = false;
|
||||||
this.jobs = [];
|
this.jobs = [];
|
||||||
this.pending = [];
|
this.pending = [];
|
||||||
@ -132,41 +131,47 @@ Chain.prototype._init = function _init() {
|
|||||||
utils.debug('Warning: %d (%dmb) orphans cleared!', count, utils.mb(size));
|
utils.debug('Warning: %d (%dmb) orphans cleared!', count, utils.mb(size));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.db.on('add entry', function(entry) {
|
||||||
|
self.emit('add entry', entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.db.on('remove entry', function(entry) {
|
||||||
|
self.emit('remove entry', entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.db.on('add block', function(block) {
|
||||||
|
self.emit('add block', block);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.db.on('remove block', function(block) {
|
||||||
|
self.emit('remove block', block);
|
||||||
|
});
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
utils.debug('Chain is loading.');
|
utils.debug('Chain is loading.');
|
||||||
|
|
||||||
this._ensureGenesis(function(err) {
|
self._preload(function(err, start) {
|
||||||
if (err)
|
if (err) {
|
||||||
throw err;
|
utils.debug('Preloading chain failed.');
|
||||||
|
utils.debug('Reason: %s', err.message);
|
||||||
|
}
|
||||||
|
|
||||||
self._preload(function(err, start) {
|
self.db.load(function(err) {
|
||||||
if (err) {
|
if (err)
|
||||||
utils.debug('Preloading chain failed.');
|
throw err;
|
||||||
utils.debug('Reason: %s', err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.db.load(function(err) {
|
self.db.getTip(function(err, tip) {
|
||||||
if (err)
|
if (err)
|
||||||
throw err;
|
throw err;
|
||||||
|
|
||||||
self._syncHeight(function(err) {
|
assert(tip);
|
||||||
if (err)
|
|
||||||
throw err;
|
|
||||||
|
|
||||||
self.db.getTip(function(err, tip) {
|
self.tip = tip;
|
||||||
if (err)
|
self.height = tip.height;
|
||||||
throw err;
|
|
||||||
|
|
||||||
assert(tip);
|
self.loading = false;
|
||||||
|
self.emit('load');
|
||||||
self.tip = tip;
|
|
||||||
self.height = tip.height;
|
|
||||||
|
|
||||||
self.loading = false;
|
|
||||||
self.emit('load');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -230,37 +235,6 @@ Chain.prototype._lock = function _lock(func, args, force) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype._ensureGenesis = function _ensureGenesis(callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
callback = utils.asyncify(callback);
|
|
||||||
|
|
||||||
if (!this.blockdb)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
self.blockdb.hasBlock(network.genesis.hash, function(err, result) {
|
|
||||||
var genesis;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
utils.debug('BlockDB does not have genesis block. Adding.');
|
|
||||||
|
|
||||||
genesis = bcoin.block.fromRaw(network.genesisBlock, 'hex');
|
|
||||||
genesis.height = 0;
|
|
||||||
|
|
||||||
self.blockdb.saveBlock(genesis, function(err) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
return callback();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Stream headers from electrum.org for quickly
|
// Stream headers from electrum.org for quickly
|
||||||
// preloading the chain. Electrum.org stores
|
// preloading the chain. Electrum.org stores
|
||||||
// headers in the standard block header format,
|
// headers in the standard block header format,
|
||||||
@ -398,24 +372,6 @@ Chain.prototype._preload = function _preload(callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype._saveBlock = function _saveBlock(block, callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if (!this.blockdb)
|
|
||||||
return utils.nextTick(callback);
|
|
||||||
|
|
||||||
this.blockdb.saveBlock(block, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype._removeBlock = function _removeBlock(tip, callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if (!this.blockdb)
|
|
||||||
return utils.nextTick(callback);
|
|
||||||
|
|
||||||
this.blockdb.removeBlock(tip, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype._verifyContext = function _verifyContext(block, prev, callback) {
|
Chain.prototype._verifyContext = function _verifyContext(block, prev, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
@ -605,18 +561,18 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
|
|||||||
var self = this;
|
var self = this;
|
||||||
var height = prev.height + 1;
|
var height = prev.height + 1;
|
||||||
|
|
||||||
if (!this.blockdb || block.type !== 'block')
|
if (this.options.spv || block.type !== 'block')
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
if (block.isGenesis())
|
if (block.isGenesis())
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
// Check all transactions
|
// Check all transactions
|
||||||
utils.every(block.txs, function(tx, next) {
|
utils.everySerial(block.txs, function(tx, next) {
|
||||||
var hash = tx.hash('hex');
|
var hash = tx.hash('hex');
|
||||||
|
|
||||||
// BIP30 - Ensure there are no duplicate txids
|
// BIP30 - Ensure there are no duplicate txids
|
||||||
self.blockdb.isUnspentTX(hash, function(err, result) {
|
self.db.isUnspentTX(hash, function(err, result) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
||||||
@ -639,7 +595,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
|
|||||||
var height = prev.height + 1;
|
var height = prev.height + 1;
|
||||||
var scriptCheck = true;
|
var scriptCheck = true;
|
||||||
|
|
||||||
if (!this.blockdb || block.type !== 'block')
|
if (this.options.spv || block.type !== 'block')
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
if (block.isGenesis())
|
if (block.isGenesis())
|
||||||
@ -652,13 +608,14 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
|
|||||||
scriptCheck = false;
|
scriptCheck = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.blockdb.fillBlock(block, function(err) {
|
this.db.fillBlock(block, function(err) {
|
||||||
var i, j, input, hash;
|
var i, j, input, hash;
|
||||||
var sigops = 0;
|
var sigops = 0;
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
|
|
||||||
// Check all transactions
|
// Check all transactions
|
||||||
for (i = 0; i < block.txs.length; i++) {
|
for (i = 0; i < block.txs.length; i++) {
|
||||||
tx = block.txs[i];
|
tx = block.txs[i];
|
||||||
@ -827,36 +784,8 @@ Chain.prototype._reorganize = function _reorganize(entry, callback) {
|
|||||||
assert(entries.length > 0);
|
assert(entries.length > 0);
|
||||||
|
|
||||||
utils.forEachSerial(entries, function(entry, next) {
|
utils.forEachSerial(entries, function(entry, next) {
|
||||||
self.db.disconnect(entry, function(err) {
|
self.db.disconnect(entry, next);
|
||||||
if (err)
|
}, callback);
|
||||||
return next(err);
|
|
||||||
|
|
||||||
self.emit('remove entry', entry);
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
}, function(err) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (!self.blockdb)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
utils.forEachSerial(entries, function(entry, next) {
|
|
||||||
self.blockdb.disconnectBlock(entry.hash, function(err, block) {
|
|
||||||
if (err)
|
|
||||||
return next(err);
|
|
||||||
|
|
||||||
self.emit('remove block', block);
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
}, function(err) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
return callback();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,39 +814,8 @@ Chain.prototype._reorganize = function _reorganize(entry, callback) {
|
|||||||
assert(entries.length > 0);
|
assert(entries.length > 0);
|
||||||
|
|
||||||
utils.forEachSerial(entries, function(entry, next) {
|
utils.forEachSerial(entries, function(entry, next) {
|
||||||
self.db.connect(entry, function(err) {
|
self.db.connect(entry, next);
|
||||||
if (err)
|
}, callback);
|
||||||
return next(err);
|
|
||||||
|
|
||||||
self.emit('add entry', entry);
|
|
||||||
|
|
||||||
return next();
|
|
||||||
});
|
|
||||||
}, function(err) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
if (!self.blockdb)
|
|
||||||
return callback();
|
|
||||||
|
|
||||||
utils.forEachSerial(entries, function(err, entry) {
|
|
||||||
self.blockdb.connectBlock(entry.hash, function(err, block) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
assert(block);
|
|
||||||
|
|
||||||
self.emit('add block', block);
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
}, function(err) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
return callback();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -951,11 +849,8 @@ Chain.prototype._setBestChain = function _setBestChain(entry, block, callback) {
|
|||||||
|
|
||||||
// Start fsyncing writes once we're no
|
// Start fsyncing writes once we're no
|
||||||
// longer dealing with historical data.
|
// longer dealing with historical data.
|
||||||
if (this.isFull()) {
|
if (this.isFull())
|
||||||
this.db.fsync = true;
|
this.db.fsync = true;
|
||||||
if (this.blockdb)
|
|
||||||
this.blockdb.fsync = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.tip) {
|
if (!this.tip) {
|
||||||
if (entry.hash !== network.genesis.hash)
|
if (entry.hash !== network.genesis.hash)
|
||||||
@ -972,19 +867,14 @@ Chain.prototype._setBestChain = function _setBestChain(entry, block, callback) {
|
|||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
self._saveBlock(block, function(err) {
|
self.db.save(entry, block, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
self.db.save(entry, function(err) {
|
self.tip = entry;
|
||||||
if (err)
|
self.height = entry.height;
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
self.tip = entry;
|
return callback();
|
||||||
self.height = entry.height;
|
|
||||||
|
|
||||||
return callback();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1014,74 +904,7 @@ Chain.prototype.reset = function reset(height, callback, force) {
|
|||||||
if (err)
|
if (err)
|
||||||
return done(err);
|
return done(err);
|
||||||
|
|
||||||
if (!self.blockdb)
|
return done();
|
||||||
return done();
|
|
||||||
|
|
||||||
self.blockdb.reset(height, function(err) {
|
|
||||||
if (err)
|
|
||||||
return done(err);
|
|
||||||
|
|
||||||
return done();
|
|
||||||
}, function(block) {
|
|
||||||
self.emit('remove block', block);
|
|
||||||
});
|
|
||||||
}, function(entry) {
|
|
||||||
self.emit('remove entry', entry);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype._syncHeight = function _syncHeight(callback, force) {
|
|
||||||
var self = this;
|
|
||||||
var chainHeight;
|
|
||||||
|
|
||||||
var unlock = this._lock(_syncHeight, [callback], force);
|
|
||||||
if (!unlock)
|
|
||||||
return;
|
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
function done(err, result) {
|
|
||||||
unlock();
|
|
||||||
callback(err, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.db.getChainHeight(function(err, chainHeight) {
|
|
||||||
if (err)
|
|
||||||
return done(err);
|
|
||||||
|
|
||||||
if (chainHeight == null || chainHeight < 0)
|
|
||||||
return done(new Error('Bad chain height.'));
|
|
||||||
|
|
||||||
if (!self.blockdb)
|
|
||||||
return done();
|
|
||||||
|
|
||||||
self.blockdb.getHeight(function(err, blockHeight) {
|
|
||||||
if (err)
|
|
||||||
return done(err);
|
|
||||||
|
|
||||||
if (blockHeight < 0)
|
|
||||||
return done(new Error('Bad block height.'));
|
|
||||||
|
|
||||||
if (blockHeight === chainHeight)
|
|
||||||
return done();
|
|
||||||
|
|
||||||
utils.debug('ChainDB and BlockDB are out of sync.');
|
|
||||||
|
|
||||||
if (blockHeight < chainHeight) {
|
|
||||||
utils.debug('ChainDB is higher than BlockDB. Syncing...');
|
|
||||||
return self.db.reset(blockHeight, done);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockHeight > chainHeight) {
|
|
||||||
utils.debug('BlockDB is higher than ChainDB. Syncing...');
|
|
||||||
self.blockdb.reset(chainHeight, function(err) {
|
|
||||||
if (err)
|
|
||||||
return done(err);
|
|
||||||
|
|
||||||
return done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1290,6 +1113,13 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the block height
|
||||||
|
// IMPORTANT!!!!!
|
||||||
|
block.height = height;
|
||||||
|
block.txs.forEach(function(tx) {
|
||||||
|
tx.height = height;
|
||||||
|
});
|
||||||
|
|
||||||
// Do "contextual" verification on our block
|
// Do "contextual" verification on our block
|
||||||
// now that we're certain its previous
|
// now that we're certain its previous
|
||||||
// block is in the chain.
|
// block is in the chain.
|
||||||
@ -1326,12 +1156,6 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
|
|||||||
if (entry.chainwork.cmp(self.tip.chainwork) <= 0)
|
if (entry.chainwork.cmp(self.tip.chainwork) <= 0)
|
||||||
return done();
|
return done();
|
||||||
|
|
||||||
// Update the block height
|
|
||||||
block.height = entry.height;
|
|
||||||
block.txs.forEach(function(tx) {
|
|
||||||
tx.height = entry.height;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Attempt to add block to the chain index.
|
// Attempt to add block to the chain index.
|
||||||
self._setBestChain(entry, block, function(err) {
|
self._setBestChain(entry, block, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
@ -1347,8 +1171,6 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
|
|||||||
if (block.hash('hex') !== initial.hash('hex'))
|
if (block.hash('hex') !== initial.hash('hex'))
|
||||||
self.emit('resolved', block, entry, peer);
|
self.emit('resolved', block, entry, peer);
|
||||||
|
|
||||||
self.emit('add block', block);
|
|
||||||
|
|
||||||
// No orphan chain.
|
// No orphan chain.
|
||||||
if (!self.orphan.map[hash])
|
if (!self.orphan.map[hash])
|
||||||
return done();
|
return done();
|
||||||
|
|||||||
1066
lib/bcoin/chaindb.js
1066
lib/bcoin/chaindb.js
File diff suppressed because it is too large
Load Diff
@ -41,13 +41,10 @@ Fullnode.prototype._init = function _init() {
|
|||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
// BlockDB technically needs access to the
|
this.chain = new bcoin.chain(this, {
|
||||||
// chain, but that's only once it's being
|
preload: false,
|
||||||
// used for tx retrieval.
|
|
||||||
this.blockdb = new bcoin.blockdb(this, {
|
|
||||||
cache: false,
|
|
||||||
fsync: false,
|
fsync: false,
|
||||||
prune: true
|
prune: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mempool needs access to blockdb.
|
// Mempool needs access to blockdb.
|
||||||
@ -55,12 +52,6 @@ Fullnode.prototype._init = function _init() {
|
|||||||
rbf: false
|
rbf: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// Chain needs access to blockdb.
|
|
||||||
this.chain = new bcoin.chain(this, {
|
|
||||||
preload: false,
|
|
||||||
fsync: false
|
|
||||||
});
|
|
||||||
|
|
||||||
// Pool needs access to the chain.
|
// Pool needs access to the chain.
|
||||||
this.pool = new bcoin.pool(this, {
|
this.pool = new bcoin.pool(this, {
|
||||||
witness: this.network.type === 'segnet',
|
witness: this.network.type === 'segnet',
|
||||||
@ -206,11 +197,11 @@ Fullnode.prototype.scanWallet = function scanWallet(wallet, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Fullnode.prototype.getBlock = function getBlock(hash, callback) {
|
Fullnode.prototype.getBlock = function getBlock(hash, callback) {
|
||||||
this.blockdb.getBlock(hash, callback);
|
this.chain.db.getBlock(hash, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Fullnode.prototype.getFullBlock = function getFullBlock(hash, callback) {
|
Fullnode.prototype.getFullBlock = function getFullBlock(hash, callback) {
|
||||||
this.blockdb.getFullBlock(hash, callback);
|
this.chain.db.getFullBlock(hash, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Fullnode.prototype.getCoin = function getCoin(hash, index, callback) {
|
Fullnode.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||||
@ -226,7 +217,7 @@ Fullnode.prototype.getCoin = function getCoin(hash, index, callback) {
|
|||||||
if (this.mempool.isSpent(hash, index))
|
if (this.mempool.isSpent(hash, index))
|
||||||
return callback(null, null);
|
return callback(null, null);
|
||||||
|
|
||||||
this.blockdb.getCoin(hash, index, function(err, coin) {
|
this.chain.db.getCoin(hash, index, function(err, coin) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -245,7 +236,7 @@ Fullnode.prototype.getCoinByAddress = function getCoinByAddress(addresses, callb
|
|||||||
|
|
||||||
mempool = this.mempool.getCoinsByAddress(addresses);
|
mempool = this.mempool.getCoinsByAddress(addresses);
|
||||||
|
|
||||||
this.blockdb.getCoinsByAddress(addresses, function(err, coins) {
|
this.chain.db.getCoinsByAddress(addresses, function(err, coins) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -267,7 +258,7 @@ Fullnode.prototype.getTX = function getTX(hash, callback) {
|
|||||||
if (tx)
|
if (tx)
|
||||||
return callback(null, tx);
|
return callback(null, tx);
|
||||||
|
|
||||||
this.blockdb.getTX(hash, function(err, tx) {
|
this.chain.db.getTX(hash, function(err, tx) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -286,7 +277,7 @@ Fullnode.prototype.isSpent = function isSpent(hash, index, callback) {
|
|||||||
if (this.mempool.isSpent(hash, index))
|
if (this.mempool.isSpent(hash, index))
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
|
|
||||||
this.blockdb.isSpent(hash, index, callback);
|
this.chain.db.isSpent(hash, index, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Fullnode.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
|
Fullnode.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
|
||||||
@ -297,7 +288,7 @@ Fullnode.prototype.getTXByAddress = function getTXByAddress(addresses, callback)
|
|||||||
|
|
||||||
mempool = this.mempool.getTXByAddress(addresses);
|
mempool = this.mempool.getTXByAddress(addresses);
|
||||||
|
|
||||||
this.blockdb.getTXByAddress(addresses, function(err, txs) {
|
this.chain.db.getTXByAddress(addresses, function(err, txs) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -311,7 +302,7 @@ Fullnode.prototype.fillCoin = function fillCoin(tx, callback) {
|
|||||||
if (this.mempool.fillCoin(tx))
|
if (this.mempool.fillCoin(tx))
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
this.blockdb.fillCoin(tx, callback);
|
this.chain.db.fillCoin(tx, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Fullnode.prototype.fillTX = function fillTX(tx, callback) {
|
Fullnode.prototype.fillTX = function fillTX(tx, callback) {
|
||||||
@ -320,7 +311,7 @@ Fullnode.prototype.fillTX = function fillTX(tx, callback) {
|
|||||||
if (this.mempool.fillTX(tx))
|
if (this.mempool.fillTX(tx))
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
this.blockdb.fillTX(tx, callback);
|
this.chain.db.fillTX(tx, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -27,7 +27,7 @@ function Mempool(node, options) {
|
|||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.blockdb = node.blockdb;
|
this.chain = node.chain;
|
||||||
|
|
||||||
this.txs = {};
|
this.txs = {};
|
||||||
this.spent = {};
|
this.spent = {};
|
||||||
@ -214,7 +214,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
|
|
||||||
this._lockTX(tx);
|
this._lockTX(tx);
|
||||||
|
|
||||||
this.blockdb.fillCoin(tx, function(err) {
|
this.chain.fillCoin(tx, function(err) {
|
||||||
var i, input, dup, height, ts, priority;
|
var i, input, dup, height, ts, priority;
|
||||||
|
|
||||||
self._unlockTX(tx);
|
self._unlockTX(tx);
|
||||||
|
|||||||
@ -1495,7 +1495,7 @@ utils.forEach = function forEach(arr, iter, callback) {
|
|||||||
utils.forRangeSerial = function forRangeSerial(from, to, iter, callback) {
|
utils.forRangeSerial = function forRangeSerial(from, to, iter, callback) {
|
||||||
var called = false;
|
var called = false;
|
||||||
|
|
||||||
callback = utils.asyncify(callback);
|
callback = utils.ensure(callback);
|
||||||
|
|
||||||
(function next(err) {
|
(function next(err) {
|
||||||
assert(!called);
|
assert(!called);
|
||||||
@ -1518,7 +1518,7 @@ utils.forEachSerial = function forEachSerial(arr, iter, callback) {
|
|||||||
var i = 0;
|
var i = 0;
|
||||||
var called = false;
|
var called = false;
|
||||||
|
|
||||||
callback = utils.asyncify(callback);
|
callback = utils.ensure(callback);
|
||||||
|
|
||||||
(function next(err) {
|
(function next(err) {
|
||||||
var item;
|
var item;
|
||||||
@ -1571,7 +1571,7 @@ utils.everySerial = function everySerial(arr, iter, callback) {
|
|||||||
var i = 0;
|
var i = 0;
|
||||||
var called = false;
|
var called = false;
|
||||||
|
|
||||||
callback = utils.asyncify(callback);
|
callback = utils.ensure(callback);
|
||||||
|
|
||||||
(function next(err, res) {
|
(function next(err, res) {
|
||||||
var item;
|
var item;
|
||||||
@ -1580,7 +1580,7 @@ utils.everySerial = function everySerial(arr, iter, callback) {
|
|||||||
called = true;
|
called = true;
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!res) {
|
||||||
called = true;
|
called = true;
|
||||||
return callback(null, false);
|
return callback(null, false);
|
||||||
}
|
}
|
||||||
@ -1593,7 +1593,7 @@ utils.everySerial = function everySerial(arr, iter, callback) {
|
|||||||
utils.nextTick(function() {
|
utils.nextTick(function() {
|
||||||
iter(item, next, i - 1);
|
iter(item, next, i - 1);
|
||||||
});
|
});
|
||||||
})();
|
})(null, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
utils.mb = function mb(size) {
|
utils.mb = function mb(size) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user