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.dependencies = ['bitcoind'];
|
||||||
|
|
||||||
DB.PREFIXES = {
|
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.loadTip(function(err) {
|
||||||
self.getMetadata(function(err, metadata) {
|
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(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;
|
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
|
* Will get a block from bitcoind and give a Bitcore Block
|
||||||
* @param {String|Number} hash - A block hash or block height
|
* @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
|
* Connects a block to the database and add indexes
|
||||||
* @param {Block} block - The bitcore block
|
* @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);
|
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
|
// Update block index
|
||||||
operations.push({
|
operations.push({
|
||||||
type: add ? 'put' : 'del',
|
type: add ? 'put' : 'del',
|
||||||
|
@ -668,7 +644,6 @@ DB.prototype.syncRewind = function(block, done) {
|
||||||
// Set the new tip
|
// Set the new tip
|
||||||
previousTip.__height = self.tip.__height - 1;
|
previousTip.__height = self.tip.__height - 1;
|
||||||
self.tip = previousTip;
|
self.tip = previousTip;
|
||||||
self.saveMetadata();
|
|
||||||
self.emit('removeblock', tip);
|
self.emit('removeblock', tip);
|
||||||
removeDone();
|
removeDone();
|
||||||
});
|
});
|
||||||
|
@ -725,8 +700,6 @@ DB.prototype.sync = function() {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
self.tip = block;
|
self.tip = block;
|
||||||
log.debug('Saving metadata');
|
|
||||||
self.saveMetadata();
|
|
||||||
log.debug('Chain added block to main chain');
|
log.debug('Chain added block to main chain');
|
||||||
self.emit('addblock', block);
|
self.emit('addblock', block);
|
||||||
setImmediate(done);
|
setImmediate(done);
|
||||||
|
|
Loading…
Reference in New Issue