diff --git a/lib/services/db.js b/lib/services/db.js index 38e7340b..b4e493b6 100644 --- a/lib/services/db.js +++ b/lib/services/db.js @@ -62,7 +62,8 @@ util.inherits(DB, Service); DB.dependencies = ['bitcoind']; DB.PREFIXES = { - BLOCKS: new Buffer('01', 'hex') + BLOCKS: new Buffer('01', 'hex'), + TIP: new Buffer('04', 'hex') }; /** @@ -109,45 +110,14 @@ DB.prototype.start = function(callback) { }); }); - // Does our database already have a tip? - self.getMetadata(function(err, metadata) { + self.loadTip(function(err) { if(err) { return callback(err); - } else if(!metadata || !metadata.tip) { - self.tip = self.genesis; - self.tip.__height = 0; - self.connectBlock(self.genesis, function(err) { - if(err) { - return callback(err); - } - - self.emit('addblock', self.genesis); - self.saveMetadata(); - self.sync(); - self.emit('ready'); - setImmediate(callback); - - }); - } else { - self.getBlock(metadata.tip, function(err, tip) { - if(err) { - log.warn( - 'Database is in an inconsistent state, a reindex is needed. Could not get current tip:', - metadata.tip - ); - return callback(err); - } - self.tip = tip; - var blockIndex = self.node.services.bitcoind.getBlockIndex(self.tip.hash); - if (!blockIndex) { - return callback(new Error('Could not get height for tip.')); - } - self.tip.__height = blockIndex.height; - self.sync(); - self.emit('ready'); - setImmediate(callback); - }); } + + self.sync(); + self.emit('ready'); + setImmediate(callback); }); }; @@ -220,6 +190,52 @@ DB.prototype.getAPIMethods = function() { return methods; }; +DB.prototype.loadTip = function(callback) { + var self = this; + + var options = { + keyEncoding: 'binary', + valueEncoding: 'binary' + }; + + self.store.get(DB.PREFIXES.TIP, options, function(err, tipData) { + if(err && err instanceof levelup.errors.NotFoundError) { + self.tip = self.genesis; + self.tip.__height = 0; + self.connectBlock(self.genesis, function(err) { + if(err) { + return callback(err); + } + + self.emit('addblock', self.genesis); + callback(); + }); + return; + } else if(err) { + return callback(err); + } + + var hash = tipData.toString('hex'); + + self.getBlock(hash, function(err, tip) { + if(err) { + log.warn('Database is in an inconsistent state, a reindex is needed. Could not get current tip:', + hash + ); + return callback(err); + } + + self.tip = tip; + var blockIndex = self.node.services.bitcoind.getBlockIndex(self.tip.hash); + if(!blockIndex) { + return callback(new Error('Could not get height for tip.')); + } + self.tip.__height = blockIndex.height; + callback(); + }); + }); +}; + /** * Will get a block from bitcoind and give a Bitcore Block * @param {String|Number} hash - A block hash or block height @@ -404,54 +420,6 @@ DB.prototype.getPrevHash = function(blockHash, callback) { }); }; -/** - * Saves metadata to the database - * @param {Function} callback - A function that accepts: Error - */ -DB.prototype.saveMetadata = function(callback) { - var self = this; - - function defaultCallback(err) { - if (err) { - self.emit('error', err); - } - } - - callback = callback || defaultCallback; - - var metadata = { - tip: self.tip ? self.tip.hash : null - }; - - this.store.put('metadata', JSON.stringify(metadata), {}, callback); - -}; - -/** - * Retrieves metadata from the database - * @param {Function} callback - A function that accepts: Error and Object - */ -DB.prototype.getMetadata = function(callback) { - var self = this; - - self.store.get('metadata', {}, function(err, data) { - if (err instanceof levelup.errors.NotFoundError) { - return callback(null, {}); - } else if (err) { - return callback(err); - } - - var metadata; - try { - metadata = JSON.parse(data); - } catch(e) { - return callback(new Error('Could not parse metadata')); - } - - callback(null, metadata); - }); -}; - /** * Connects a block to the database and add indexes * @param {Block} block - The bitcore block @@ -506,6 +474,14 @@ DB.prototype.runAllBlockHandlers = function(block, add, callback) { this.subscriptions.block[i].emit('db/block', block.hash); } + // Update tip + var tipHash = add ? new Buffer(block.hash, 'hex') : BufferUtil.reverse(block.header.prevHash); + operations.push({ + type: 'put', + key: DB.PREFIXES.TIP, + value: tipHash + }); + // Update block index operations.push({ type: add ? 'put' : 'del', @@ -668,7 +644,6 @@ DB.prototype.syncRewind = function(block, done) { // Set the new tip previousTip.__height = self.tip.__height - 1; self.tip = previousTip; - self.saveMetadata(); self.emit('removeblock', tip); removeDone(); }); @@ -725,8 +700,6 @@ DB.prototype.sync = function() { return done(err); } self.tip = block; - log.debug('Saving metadata'); - self.saveMetadata(); log.debug('Chain added block to main chain'); self.emit('addblock', block); setImmediate(done);