diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 545fb537..ca11ae2d 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -45,40 +45,22 @@ function Chain(options) { this.index = { heights: {}, - count: this.db.count(), + count: 0, lastTs: 0 }; this.request = new utils.RequestCache(); - this.fromJSON({ - v: 2, - type: 'chain', - network: network.type, - entries: [ - { - hash: network.genesis.hash, - version: network.genesis.version, - prevBlock: network.genesis.prevBlock, - merkleRoot: network.genesis.merkleRoot, - ts: network.genesis.ts, - bits: network.genesis.bits, - nonce: network.genesis.nonce, - height: 0 - } - ] - }); - - if (process.env.BCOIN_START_HEIGHT) { - this.storage = null; - if (network.type === 'main') - this.fromJSON(require('./protocol/preload-full')); - else if (network.type === 'testnet') - this.fromJSON(require('./protocol/preload-test-full')); - this.resetHeight(+process.env.BCOIN_START_HEIGHT); - } - - this.tip = this.db.get(this.index.count - 1); + this._addIndex(ChainBlock.fromJSON(this, { + hash: network.genesis.hash, + version: network.genesis.version, + prevBlock: network.genesis.prevBlock, + merkleRoot: network.genesis.merkleRoot, + ts: network.genesis.ts, + bits: network.genesis.bits, + nonce: network.genesis.nonce, + height: 0 + }), true); // Last TS after preload, needed for fill percent this.index.lastTs = this.tip.ts; @@ -121,44 +103,24 @@ Chain.prototype._init = function _init() { this.loading = true; - if (!this.storage) { - utils.nextTick(function() { - self.loading = false; - self.emit('load'); - }); - return; - } + utils.debug('Chain is loading.'); utils.nextTick(function() { - utils.debug('Chain is loading.'); - }); + var count = self.db.count(); + var i, entry; - s = this.storage.createReadStream({ - start: this.prefix, - end: this.prefix + 'z' - }); + for (i = 1; i < self.index.count; i++) + self._addIndex(self.db.get(i)); - s.on('data', function(data) { - data.value.hash = data.key.slice(self.prefix.length); - self._addIndex(ChainBlock.fromJSON(self, data.value)); - }); - - s.on('error', function(err) { - self.emit('error', err); - }); - - s.on('end', function() { self.loading = false; self.emit('load'); utils.debug('Chain successfully loaded.'); }); }; -Chain.prototype.getEntry = function getEntry(height) { -}; - Chain.prototype._addIndex = function _addIndex(entry, save) { var self = this; + var existing; // Already added if (this.index.heights[entry.hash] != null) { @@ -167,7 +129,7 @@ Chain.prototype._addIndex = function _addIndex(entry, save) { } // Duplicate height - var existing = this.db.get(entry.height); + existing = this.db.get(entry.height); if (existing && existing.hash === entry.hash) return Chain.codes.unchanged; @@ -185,7 +147,9 @@ Chain.prototype._addIndex = function _addIndex(entry, save) { } } - this.db.save(entry); + if (save) + this.db.save(entry); + this.index.heights[entry.hash] = entry.height; this.index.count++; @@ -257,7 +221,7 @@ Chain.prototype.resetTime = function resetTime(ts) { Chain.prototype.add = function add(block, peer) { var initial = block; var code = Chain.codes.unchanged; - var hash, prevHash, prevHeight, entry, tip; + var hash, prevHash, prevHeight, entry, tip, existing; var total = 0; for (;;) { @@ -329,7 +293,7 @@ Chain.prototype.add = function add(block, peer) { // Add entry if we do not have it (or if // there is another entry at its height) - var existing = this.db.get(entry.height); + existing = this.db.get(entry.height); if (!existing || existing.hash !== hash) { assert(this.index.heights[entry.hash] == null); @@ -342,7 +306,6 @@ Chain.prototype.add = function add(block, peer) { // The tip has more chainwork, it is a // higher height than the entry. This is // not an alternate tip. Ignore it. - if (0) if (this.tip.chainwork.cmp(entry.chainwork) > 0) { code = Chain.codes.unchanged; break; @@ -474,12 +437,25 @@ Chain.prototype.byHash = function byHash(hash) { }; Chain.prototype.byTime = function byTime(ts) { - for (var i = this.index.count - 1; i >= 0; i--) { - var existing = this.db.get(i); + var i, delta, existing; + var step = 1; + + if (ts >= this.tip.ts) + return this.tip; + + for (i = this.index.count - 1; i >= 0; i -= step) { + existing = this.db.get(i); + if (ts >= existing.ts) return existing; + + delta = existing.ts - ts; + // If they're more than 1000 blocks apart + if (delta > 1000 * 60 * 10) + step *= 2; } - return null; + + return this.db.get(0); }; Chain.prototype.hasBlock = function hasBlock(hash) { @@ -540,7 +516,7 @@ Chain.prototype.locatorHashes = function locatorHashes(start) { var hashes = []; var top = this.height(); var step = 1; - var i; + var i, existing; if (start) { if (utils.isBuffer(start)) @@ -564,11 +540,11 @@ Chain.prototype.locatorHashes = function locatorHashes(start) { top = start; } - // assert(chain[top]); + assert(this.db.get(top)); i = top; for (;;) { - var existing = this.db.get(i); + existing = this.db.get(i); if (existing) hashes.push(existing.hash); i = i - step; @@ -709,7 +685,7 @@ Chain.prototype.fromJSON = function fromJSON(json) { assert.equal(json.network, network.type); json.entries.forEach(function(entry) { - this._addIndex(ChainBlock.fromJSON(this, entry), true); + this._addIndex(ChainBlock.fromJSON(this, entry)); }, this); }; @@ -717,8 +693,8 @@ Chain.prototype.fromJSON = function fromJSON(json) { * ChainDB */ -var BLOCK_SIZE = 80; -// var BLOCK_SIZE = 144; +// var BLOCK_SIZE = 80; +var BLOCK_SIZE = 112; function ChainDB(chain) { var exists; @@ -952,8 +928,8 @@ function ChainBlock(chain, data) { this.bits = data.bits; this.nonce = data.nonce; this.height = data.height; - this.chainwork = data.chainwork || new bn(0); - // this.chainwork = data.chainwork || this.getChainwork(); + // this.chainwork = data.chainwork || new bn(0); + this.chainwork = data.chainwork || this.getChainwork(); } ChainBlock.prototype.__defineGetter__('prev', function() { @@ -1041,8 +1017,7 @@ ChainBlock.prototype.toRaw = function toRaw() { utils.writeU32(res, this.ts, 68); utils.writeU32(res, this.bits, 72); utils.writeU32(res, this.nonce, 76); - // utils.copy(utils.toArray(this.hash, 'hex'), res, 80); - // utils.copy(this.chainwork.toArray('be', 32), res, 112); + utils.copy(this.chainwork.toArray('be', 32), res, 80); return res; }; @@ -1057,8 +1032,7 @@ ChainBlock.fromRaw = function fromRaw(chain, height, p) { bits: utils.readU32(p, 72), nonce: utils.readU32(p, 76), height: height, - // hash: utils.toHex(utils.toArray(p.slice(80, 112))), - // chainwork: new bn(p.slice(112, 144)) + chainwork: new bn(p.slice(80, 112)) }); };