save tip as part of block db operations
This commit is contained in:
parent
68b0120319
commit
3fa1340ef3
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue