Restore blockchain from database
This commit is contained in:
parent
db17accf98
commit
7102e63933
@ -4,21 +4,19 @@ var bitcore = require('bitcore');
|
||||
var $ = bitcore.util.preconditions;
|
||||
var _ = bitcore.deps._;
|
||||
|
||||
var NULL = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
|
||||
function BlockChain() {
|
||||
this.tip = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
this.work = {
|
||||
'0000000000000000000000000000000000000000000000000000000000000000': 0
|
||||
};
|
||||
this.height = {
|
||||
'0000000000000000000000000000000000000000000000000000000000000000': -1
|
||||
};
|
||||
this.hashByHeight = {
|
||||
'-1': '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
};
|
||||
this.tip = NULL;
|
||||
this.work = { NULL: 0 };
|
||||
this.height = { NULL: -1 };
|
||||
this.hashByHeight = { '-1': NULL };
|
||||
this.next = {};
|
||||
this.prev = {};
|
||||
}
|
||||
|
||||
BlockChain.NULL = NULL;
|
||||
|
||||
BlockChain.fromObject = function(obj) {
|
||||
var blockchain = new BlockChain();
|
||||
blockchain.tip = obj.tip;
|
||||
|
||||
11
lib/node.js
11
lib/node.js
@ -61,11 +61,14 @@ var BitcoreNode = function(bus, networkMonitor, blockService, transactionService
|
||||
return;
|
||||
}
|
||||
var blockchainChanges = self.blockchain.proposeNewBlock(block);
|
||||
var height = self.blockchain.height[block.id];
|
||||
if (height % 100 === 0) {
|
||||
console.log('block', block.id, 'height', height);
|
||||
|
||||
// Annotate block with extra data from the chain
|
||||
block.height = self.blockchain.height[block.id];
|
||||
block.work = self.blockchain.work[block.id];
|
||||
|
||||
if (block.height % 100 === 0) {
|
||||
console.log('block', block.id, 'height', block.height);
|
||||
}
|
||||
block.height = height;
|
||||
|
||||
return Promise.each(blockchainChanges.unconfirmed, function(hash) {
|
||||
return self.blockService.unconfirm(self.blockCache[hash]);
|
||||
|
||||
@ -9,6 +9,7 @@ var Transaction = bitcore.Transaction;
|
||||
var config = require('config');
|
||||
|
||||
var errors = require('../errors');
|
||||
var BlockChain = require('../blockchain');
|
||||
|
||||
var $ = bitcore.util.preconditions;
|
||||
var JSUtil = bitcore.util.js;
|
||||
@ -40,7 +41,7 @@ var Index = {
|
||||
next: 'nxt-', // nxt-<hash> -> hash for the next block in the main chain that is a child
|
||||
height: 'bh-', // bh-<hash> -> height (-1 means disconnected)
|
||||
tip: 'tip', // tip -> { hash: hex, height: int }, the latest tip
|
||||
blockchain: 'chain'
|
||||
work: 'wk-' // wk-<hash> -> amount of work for block
|
||||
};
|
||||
_.extend(Index, {
|
||||
getNextBlock: helper(Index.next),
|
||||
@ -220,29 +221,20 @@ BlockService.prototype.onBlock = function(block) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Save a new block
|
||||
*
|
||||
* @param {bitcore.Block} block
|
||||
* @return {Promise<Block>} a promise of the same block, for chaining
|
||||
*/
|
||||
BlockService.prototype.unconfirm = function(block) {
|
||||
// TODO: unconfirm previous tip, confirm new tip.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set a block as the current tip of the blockchain
|
||||
*
|
||||
* @param {bitcore.Block} block
|
||||
* @param {Array=} ops
|
||||
* @return {Promise<Block>} a promise of the same block, for chaining
|
||||
*/
|
||||
BlockService.prototype.confirm = function(block) {
|
||||
BlockService.prototype.confirm = function(block, ops) {
|
||||
$.checkArgument(block instanceof bitcore.Block);
|
||||
|
||||
var self = this;
|
||||
|
||||
var ops = [];
|
||||
ops = ops || [];
|
||||
|
||||
//console.log(0);
|
||||
return Promise.try(function() {
|
||||
@ -250,7 +242,10 @@ BlockService.prototype.confirm = function(block) {
|
||||
self._setNextBlock(ops, block.header.prevHash, block);
|
||||
|
||||
//console.log(3);
|
||||
self._setBlockHeight(ops, block, block.height);
|
||||
self._setBlockHeight(ops, block);
|
||||
|
||||
//console.log(3);
|
||||
self._setBlockWork(ops, block);
|
||||
|
||||
//console.log(4);
|
||||
self._setBlockByTs(ops, block);
|
||||
@ -287,11 +282,19 @@ BlockService.prototype._setNextBlock = function(ops, prevBlockHash, block) {
|
||||
});
|
||||
};
|
||||
|
||||
BlockService.prototype._setBlockHeight = function(ops, block, height) {
|
||||
BlockService.prototype._setBlockHeight = function(ops, block) {
|
||||
ops.push({
|
||||
type: 'put',
|
||||
key: Index.getBlockHeight(block),
|
||||
value: height
|
||||
value: block.height
|
||||
});
|
||||
};
|
||||
|
||||
BlockService.prototype._setBlockWork = function(ops, block) {
|
||||
ops.push({
|
||||
type: 'put',
|
||||
key: Index.getBlockWork(block),
|
||||
value: block.work
|
||||
});
|
||||
};
|
||||
|
||||
@ -333,6 +336,36 @@ BlockService.prototype._setBlockByTs = function(ops, block) {
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Unconfirm a block
|
||||
*
|
||||
* @param {bitcore.Block} block
|
||||
* @param {Array=} ops
|
||||
* @return {Promise<Block>} a promise of the same block, for chaining
|
||||
*/
|
||||
BlockService.prototype.unconfirm = function(block, ops) {
|
||||
|
||||
ops = ops || [];
|
||||
|
||||
return Promise.try(function() {
|
||||
|
||||
self._removeNextBlock(ops, block.header.prevHash, block);
|
||||
|
||||
self._unsetBlockHeight(ops, block, block.height);
|
||||
|
||||
self._dropBlockByTs(ops, block);
|
||||
|
||||
return Promise.all(block.transactions.map(function(transaction) {
|
||||
return self.transactionService._unconfirmTransaction(ops, block, transaction);
|
||||
}));
|
||||
|
||||
}).then(function() {
|
||||
|
||||
return self.database.batchAsync(ops);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the block hash that forms part of the current main chain that confirmed a given
|
||||
* transaction.
|
||||
@ -368,24 +401,57 @@ BlockService.prototype.getBlockForTransaction = function(transaction) {
|
||||
|
||||
BlockService.prototype.getBlockchain = function() {
|
||||
var self = this;
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
self.database.getAsync(Index.blockchain).then(function(blockchain) {
|
||||
blockchain = BlockChain.fromObject(JSON.parse(blockchain));
|
||||
return resolve(blockchain);
|
||||
}).catch(function(arg) {
|
||||
if (arg.message.indexOf('Key not found in database') !== -1) {
|
||||
return resolve();
|
||||
|
||||
var blockchain = new BlockChain();
|
||||
|
||||
var fetchBlock = function(blockHash) {
|
||||
return Promise.all([
|
||||
function() {
|
||||
return self.database.getAsync(Index.getPreviousBlock(blockHash)).then(function(prevHash) {
|
||||
blockchain.prev[blockHash] = prevHash;
|
||||
blockchain.next[prevHash] = blockHash;
|
||||
});
|
||||
},
|
||||
function() {
|
||||
return self.database.getAsync(Index.getBlockHeight(blockHash)).then(function(height) {
|
||||
blockchain.height[blockHash] = height;
|
||||
blockchain.hashByHeight[height] = blockHash;
|
||||
});
|
||||
},
|
||||
function() {
|
||||
return self.database.getAsync(Index.getWork(blockHash)).then(function(work) {
|
||||
blockchain.work[blockHash] = work;
|
||||
});
|
||||
}
|
||||
]).then(function() {
|
||||
return blockHash;
|
||||
});
|
||||
};
|
||||
|
||||
var fetchUnlessGenesis = function(blockHash) {
|
||||
return fetchBlock(blockHash).then(function() {
|
||||
if (blockchain.prev[blockHash] === BlockChain.NULL) {
|
||||
return;
|
||||
} else {
|
||||
return fetchUnlessGenesis(blockchain.prev[blockHash]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return self.database.getAsync(Index.tip)
|
||||
.catch(function(err) {
|
||||
if (err.notFound) {
|
||||
return undefined;
|
||||
}
|
||||
return reject(arg);
|
||||
throw err;
|
||||
})
|
||||
.then(function(tip) {
|
||||
blockchain.tip = tip;
|
||||
return fetchUnlessGenesis(tip);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
BlockService.prototype.saveBlockchain = function(blockchain) {
|
||||
return this.database.putAsync({
|
||||
key: Index.blockchain,
|
||||
value: blockchain.toJSON()
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = BlockService;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user