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.util.preconditions;
|
||||||
var _ = bitcore.deps._;
|
var _ = bitcore.deps._;
|
||||||
|
|
||||||
|
var NULL = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
|
|
||||||
function BlockChain() {
|
function BlockChain() {
|
||||||
this.tip = '0000000000000000000000000000000000000000000000000000000000000000';
|
this.tip = NULL;
|
||||||
this.work = {
|
this.work = { NULL: 0 };
|
||||||
'0000000000000000000000000000000000000000000000000000000000000000': 0
|
this.height = { NULL: -1 };
|
||||||
};
|
this.hashByHeight = { '-1': NULL };
|
||||||
this.height = {
|
|
||||||
'0000000000000000000000000000000000000000000000000000000000000000': -1
|
|
||||||
};
|
|
||||||
this.hashByHeight = {
|
|
||||||
'-1': '0000000000000000000000000000000000000000000000000000000000000000'
|
|
||||||
};
|
|
||||||
this.next = {};
|
this.next = {};
|
||||||
this.prev = {};
|
this.prev = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockChain.NULL = NULL;
|
||||||
|
|
||||||
BlockChain.fromObject = function(obj) {
|
BlockChain.fromObject = function(obj) {
|
||||||
var blockchain = new BlockChain();
|
var blockchain = new BlockChain();
|
||||||
blockchain.tip = obj.tip;
|
blockchain.tip = obj.tip;
|
||||||
|
|||||||
11
lib/node.js
11
lib/node.js
@ -61,11 +61,14 @@ var BitcoreNode = function(bus, networkMonitor, blockService, transactionService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var blockchainChanges = self.blockchain.proposeNewBlock(block);
|
var blockchainChanges = self.blockchain.proposeNewBlock(block);
|
||||||
var height = self.blockchain.height[block.id];
|
|
||||||
if (height % 100 === 0) {
|
// Annotate block with extra data from the chain
|
||||||
console.log('block', block.id, 'height', height);
|
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 Promise.each(blockchainChanges.unconfirmed, function(hash) {
|
||||||
return self.blockService.unconfirm(self.blockCache[hash]);
|
return self.blockService.unconfirm(self.blockCache[hash]);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var Transaction = bitcore.Transaction;
|
|||||||
var config = require('config');
|
var config = require('config');
|
||||||
|
|
||||||
var errors = require('../errors');
|
var errors = require('../errors');
|
||||||
|
var BlockChain = require('../blockchain');
|
||||||
|
|
||||||
var $ = bitcore.util.preconditions;
|
var $ = bitcore.util.preconditions;
|
||||||
var JSUtil = bitcore.util.js;
|
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
|
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)
|
height: 'bh-', // bh-<hash> -> height (-1 means disconnected)
|
||||||
tip: 'tip', // tip -> { hash: hex, height: int }, the latest tip
|
tip: 'tip', // tip -> { hash: hex, height: int }, the latest tip
|
||||||
blockchain: 'chain'
|
work: 'wk-' // wk-<hash> -> amount of work for block
|
||||||
};
|
};
|
||||||
_.extend(Index, {
|
_.extend(Index, {
|
||||||
getNextBlock: helper(Index.next),
|
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
|
* Set a block as the current tip of the blockchain
|
||||||
*
|
*
|
||||||
* @param {bitcore.Block} block
|
* @param {bitcore.Block} block
|
||||||
|
* @param {Array=} ops
|
||||||
* @return {Promise<Block>} a promise of the same block, for chaining
|
* @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);
|
$.checkArgument(block instanceof bitcore.Block);
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var ops = [];
|
ops = ops || [];
|
||||||
|
|
||||||
//console.log(0);
|
//console.log(0);
|
||||||
return Promise.try(function() {
|
return Promise.try(function() {
|
||||||
@ -250,7 +242,10 @@ BlockService.prototype.confirm = function(block) {
|
|||||||
self._setNextBlock(ops, block.header.prevHash, block);
|
self._setNextBlock(ops, block.header.prevHash, block);
|
||||||
|
|
||||||
//console.log(3);
|
//console.log(3);
|
||||||
self._setBlockHeight(ops, block, block.height);
|
self._setBlockHeight(ops, block);
|
||||||
|
|
||||||
|
//console.log(3);
|
||||||
|
self._setBlockWork(ops, block);
|
||||||
|
|
||||||
//console.log(4);
|
//console.log(4);
|
||||||
self._setBlockByTs(ops, block);
|
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({
|
ops.push({
|
||||||
type: 'put',
|
type: 'put',
|
||||||
key: Index.getBlockHeight(block),
|
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
|
* Retrieve the block hash that forms part of the current main chain that confirmed a given
|
||||||
* transaction.
|
* transaction.
|
||||||
@ -368,24 +401,57 @@ BlockService.prototype.getBlockForTransaction = function(transaction) {
|
|||||||
|
|
||||||
BlockService.prototype.getBlockchain = function() {
|
BlockService.prototype.getBlockchain = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
self.database.getAsync(Index.blockchain).then(function(blockchain) {
|
|
||||||
blockchain = BlockChain.fromObject(JSON.parse(blockchain));
|
var blockchain = new BlockChain();
|
||||||
return resolve(blockchain);
|
|
||||||
}).catch(function(arg) {
|
var fetchBlock = function(blockHash) {
|
||||||
if (arg.message.indexOf('Key not found in database') !== -1) {
|
return Promise.all([
|
||||||
return resolve();
|
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;
|
module.exports = BlockService;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user