Merge pull request #301 from matiaspando/bug/bitcoindVersion

Checking Bitcoin Core version
This commit is contained in:
Matias Alejo Garcia 2015-03-30 10:08:38 -03:00
commit 1263ab0148
3 changed files with 131 additions and 97 deletions

View File

@ -1,3 +1,4 @@
# *insight API*
*insight API* is an open-source bitcoin blockchain REST
@ -12,6 +13,10 @@ require certain information from the blockchain that bitcoind does not provide.
A blockchain explorer front-end has been developed on top of *Insight API*. It can
be downloaded at [Github Insight Repository](https://github.com/bitpay/insight).
## Warning
Insight file sync does not work with **bitcoind** v0.10
In order to use Insigtht you must set the environment variable INSIGHT_FORCE_RPC_SYNC = 1
We are working on `bitcore-node` to replace Insight-api. Check `bitcore-node` on [github](https://github.com/bitpay/bitcore-node).
## Prerequisites
@ -32,6 +37,7 @@ bitcoind must be running and must have finished downloading the blockchain **bef
* **NPM** - Node.js package manager, should be automatically installed when you get node.js.
## Quick Install
Check the Prerequisites section above before installing.

View File

@ -50,6 +50,7 @@ switch (process.env.NODE_ENV) {
}
var network = process.env.INSIGHT_NETWORK || 'testnet';
var forceRPCsync = process.env.INSIGHT_FORCE_RPC_SYNC;
var dataDir = process.env.BITCOIND_DATADIR;
var isWin = /^win/.test(process.platform);
@ -133,4 +134,5 @@ module.exports = {
},
safeConfirmations: safeConfirmations, // PLEASE NOTE THAT *FULL RESYNC* IS NEEDED TO CHANGE safeConfirmations
ignoreCache: ignoreCache,
forceRPCsync: forceRPCsync,
};

View File

@ -1,20 +1,20 @@
'use strict';
var imports = require('soop').imports();
var util = require('util');
var async = require('async');
var imports = require('soop').imports();
var util = require('util');
var async = require('async');
var bitcore = require('bitcore');
var networks = bitcore.networks;
var config = imports.config || require('../config/config');
var Sync = require('./Sync');
var sockets = require('../app/controllers/socket.js');
var bitcore = require('bitcore');
var networks = bitcore.networks;
var config = imports.config || require('../config/config');
var Sync = require('./Sync');
var sockets = require('../app/controllers/socket.js');
var BlockExtractor = require('./BlockExtractor.js');
var buffertools = require('buffertools');
var bitcoreUtil = bitcore.util;
var buffertools = require('buffertools');
var bitcoreUtil = bitcore.util;
var logger = require('./logger').logger;
var info = logger.info;
var error = logger.error;
var info = logger.info;
var error = logger.error;
var PERCENTAGE_TO_START_FROM_RPC = 0.96;
// TODO TODO TODO
@ -24,34 +24,62 @@ var PERCENTAGE_TO_START_FROM_RPC = 0.96;
var BAD_GEN_ERROR = 'Bad genesis block. Network mismatch between Insight and bitcoind? Insight is configured for:';
var BAD_GEN_ERROR_DB = 'Bad genesis block. Network mismatch between Insight and levelDB? Insight is configured for:';
function HistoricSync(opts) {
opts = opts || {};
this.shouldBroadcast = opts.shouldBroadcastSync;
this.network = config.network === 'testnet' ? networks.testnet: networks.livenet;
this.network = config.network === 'testnet' ? networks.testnet : networks.livenet;
var genesisHashReversed = new Buffer(32);
this.network.genesisBlock.hash.copy(genesisHashReversed);
buffertools.reverse(genesisHashReversed);
this.genesis = genesisHashReversed.toString('hex');
var bitcore = require('bitcore');
var RpcClient = bitcore.RpcClient;
var bitcore = require('bitcore');
var RpcClient = bitcore.RpcClient;
this.rpc = new RpcClient(config.bitcoind);
this.getBitcoinCoreVersion(function(bitcoinVersion) {
if (bitcoinVersion > 100000 && !config.forceRPCsync) {
info('-------------------------------------------------------');
info('- Bitcoin Core version >0.10 only works with RPC sync -');
info('- Set the env variable INSIGHT_FORCE_RPC_SYNC = 1 -');
info('-------------------------------------------------------');
process.exit(1);
} else {
info('Bitcoin Core version ', bitcoinVersion);
info('Using RPC sync ');
}
});
this.sync = new Sync(opts);
this.height =0;
this.height = 0;
}
HistoricSync.prototype.getBitcoinCoreVersion = function(cb) {
var self = this;
self.rpc.getInfo(function(err, info) {
if (err) {
error('ERROR ', err);
process.exit(-1);
};
return cb(info.result.version);
});
};
HistoricSync.prototype.showProgress = function() {
var self = this;
if ( self.status ==='syncing' &&
( self.height ) % self.step !== 1) return;
if (self.status === 'syncing' &&
(self.height) % self.step !== 1) return;
if (self.error)
if (self.error)
error(self.error);
else {
self.updatePercentage();
info(util.format('status: [%d%%]', self.syncPercentage));
@ -68,8 +96,8 @@ HistoricSync.prototype.showProgress = function() {
HistoricSync.prototype.setError = function(err) {
var self = this;
self.error = err.message?err.message:err.toString();
self.status='error';
self.error = err.message ? err.message : err.toString();
self.status = 'error';
self.showProgress();
return err;
};
@ -97,7 +125,7 @@ HistoricSync.prototype.info = function() {
};
HistoricSync.prototype.updatePercentage = function() {
var r = this.height / this.blockChainHeight;
var r = this.height / this.blockChainHeight;
this.syncPercentage = parseFloat(100 * r).toFixed(3);
if (this.syncPercentage > 100) this.syncPercentage = 100;
};
@ -115,11 +143,10 @@ HistoricSync.prototype.getBlockFromRPC = function(cb) {
// this is to match block retreived from file
if (blockInfo.hash === self.genesis)
blockInfo.previousblockhash =
self.network.genesisBlock.prev_hash.toString('hex');
self.network.genesisBlock.prev_hash.toString('hex');
self.currentRpcHash = blockInfo.nextblockhash;
}
else {
} else {
blockInfo = null;
}
return cb(null, blockInfo);
@ -135,9 +162,9 @@ HistoricSync.prototype.getStandardizedBlock = function(b) {
time: b.timestamp,
};
var isCoinBase = 1;
block.tx = b.txs.map(function(tx){
block.tx = b.txs.map(function(tx) {
var ret = self.sync.txDb.getStandardizedTx(tx, b.timestamp, isCoinBase);
isCoinBase=0;
isCoinBase = 0;
return ret;
});
return block;
@ -150,10 +177,10 @@ HistoricSync.prototype.getBlockFromFile = function(cb) {
//get Info
self.blockExtractor.getNextBlock(function(err, b) {
if (err || ! b) return cb(err);
if (err || !b) return cb(err);
blockInfo = self.getStandardizedBlock(b);
self.sync.bDb.setLastFileIndex(self.blockExtractor.currentFileIndex, function(err) {
return cb(err,blockInfo);
return cb(err, blockInfo);
});
});
};
@ -174,16 +201,16 @@ HistoricSync.prototype.checkNetworkSettings = function(next) {
self.hasGenesis = false;
// check network config
self.rpc.getBlockHash(0, function(err, res){
if (!err && ( res && res.result !== self.genesis)) {
self.rpc.getBlockHash(0, function(err, res) {
if (!err && (res && res.result !== self.genesis)) {
err = new Error(BAD_GEN_ERROR + config.network);
}
if (err) return next(err);
self.sync.bDb.has(self.genesis, function(err, b) {
if (!err && ( res && res.result !== self.genesis)) {
if (!err && (res && res.result !== self.genesis)) {
err = new Error(BAD_GEN_ERROR_DB + config.network);
}
self.hasGenesis = b?true:false;
self.hasGenesis = b ? true : false;
return next(err);
});
});
@ -200,13 +227,12 @@ HistoricSync.prototype.updateStartBlock = function(opts, next) {
if (blockInfo.height) {
self.startBlock = opts.startAt;
self.height = blockInfo.height;
info('Resuming sync from block: %s #%d',opts.startAt, self.height);
info('Resuming sync from block: %s #%d', opts.startAt, self.height);
return next(err);
}
});
}
else {
self.sync.bDb.getTip(function(err,tip, height) {
} else {
self.sync.bDb.getTip(function(err, tip, height) {
if (!tip) return next();
var blockInfo;
@ -227,29 +253,28 @@ HistoricSync.prototype.updateStartBlock = function(opts, next) {
if (err) return next(err);
var ret = false;
var d = Math.abs(height-blockInfo.height);
if (d>6) {
error('Previous Tip block tip height differs by %d. Please delete and resync (-D)',d);
var d = Math.abs(height - blockInfo.height);
if (d > 6) {
error('Previous Tip block tip height differs by %d. Please delete and resync (-D)', d);
process.exit(1);
}
if ( self.blockChainHeight === blockInfo.height ||
blockInfo.confirmations > 0) {
if (self.blockChainHeight === blockInfo.height ||
blockInfo.confirmations > 0) {
ret = false;
}
else {
} else {
oldtip = tip;
if (!tip)
throw new Error('Previous blockchain tip was not found on bitcoind. Please reset Insight DB. Tip was:'+tip)
throw new Error('Previous blockchain tip was not found on bitcoind. Please reset Insight DB. Tip was:' + tip)
tip = blockInfo.previousblockhash;
info('Previous TIP is now orphan. Back to:' + tip);
ret = true;
ret = true;
}
return ret;
},
function(err) {
self.startBlock = tip;
self.height = height;
info('Resuming sync from block: %s #%d',tip,height);
info('Resuming sync from block: %s #%d', tip, height);
return next(err);
}
);
@ -260,12 +285,14 @@ HistoricSync.prototype.updateStartBlock = function(opts, next) {
HistoricSync.prototype.prepareFileSync = function(opts, next) {
var self = this;
if ( opts.forceRPC || !config.bitcoind.dataDir ||
if (config.forceRPCsync) return next();
if (opts.forceRPC || !config.bitcoind.dataDir ||
self.height > self.blockChainHeight * PERCENTAGE_TO_START_FROM_RPC) return next();
try {
self.blockExtractor = new BlockExtractor(config.bitcoind.dataDir, config.network);
self.blockExtractor = new BlockExtractor(config.bitcoind.dataDir, config.network);
} catch (e) {
info(e.message + '. Disabling file sync.');
return next();
@ -287,15 +314,15 @@ HistoricSync.prototype.prepareFileSync = function(opts, next) {
function() {
return h !== self.startBlock;
},
function (w_cb) {
self.getBlockFromFile(function(err,b) {
function(w_cb) {
self.getBlockFromFile(function(err, b) {
if (!b) return w_cb('Could not find block ' + self.startBlock);
h=b.hash;
setImmediate(function(){
h = b.hash;
setImmediate(function() {
return w_cb(err);
});
});
}, function(err){
}, function(err) {
console.log('\tFOUND Starting Block!');
// TODO SET HEIGHT
@ -311,7 +338,7 @@ HistoricSync.prototype.prepareRpcSync = function(opts, next) {
if (self.blockExtractor) return next();
self.getFn = self.getBlockFromRPC;
self.allowReorgs = true;
self.currentRpcHash = self.startBlock;
self.currentRpcHash = self.startBlock;
return next();
};
@ -324,8 +351,7 @@ HistoricSync.prototype.showSyncStartMessage = function() {
if (self.blockExtractor) {
info('bitcoind dataDir configured...importing blocks from .dat files');
info('First file index: ' + self.blockExtractor.currentFileIndex);
}
else {
} else {
info('syncing from RPC (slow)');
}
@ -337,20 +363,20 @@ HistoricSync.prototype.showSyncStartMessage = function() {
HistoricSync.prototype.setupSyncStatus = function() {
var self = this;
var step = parseInt( (self.blockChainHeight - self.height) / 1000);
var step = parseInt((self.blockChainHeight - self.height) / 1000);
if (step < 10) step = 10;
self.step = step;
self.type = self.blockExtractor?'from .dat Files':'from RPC calls';
self.type = self.blockExtractor ? 'from .dat Files' : 'from RPC calls';
self.status = 'syncing';
self.startTs = Date.now();
self.endTs = null;
this.error = null;
self.endTs = null;
this.error = null;
this.syncPercentage = 0;
};
HistoricSync.prototype.checkDBVersion = function(cb) {
this.sync.txDb.checkVersion02(function(isOk){
this.sync.txDb.checkVersion02(function(isOk) {
if (!isOk) {
console.log('\n#############################\n\n ## Insight API DB is older that v0.2. Please resync using:\n $ util/sync.js -D\n More information at Insight API\'s Readme.md');
process.exit(1);
@ -366,39 +392,40 @@ HistoricSync.prototype.prepareToSync = function(opts, next) {
self.status = 'starting';
async.series([
function(s_c) {
self.checkDBVersion(s_c);
},
function(s_c) {
self.checkNetworkSettings(s_c);
},
function(s_c) {
self.updateBlockChainHeight(s_c);
},
function(s_c) {
self.updateStartBlock(opts,s_c);
},
function(s_c) {
self.prepareFileSync(opts, s_c);
},
function(s_c) {
self.prepareRpcSync(opts, s_c);
},
],
function(err) {
if (err) return(self.setError(err));
self.showSyncStartMessage();
self.setupSyncStatus();
return next();
});
function(s_c) {
self.checkDBVersion(s_c);
},
function(s_c) {
self.checkNetworkSettings(s_c);
},
function(s_c) {
self.updateBlockChainHeight(s_c);
},
function(s_c) {
self.updateStartBlock(opts, s_c);
},
function(s_c) {
self.prepareFileSync(opts, s_c);
},
function(s_c) {
self.prepareRpcSync(opts, s_c);
},
],
function(err) {
if (err) return (self.setError(err));
self.showSyncStartMessage();
self.setupSyncStatus();
return next();
});
};
HistoricSync.prototype.start = function(opts, next) {
var self = this;
if (self.status==='starting' || self.status==='syncing') {
if (self.status === 'starting' || self.status === 'syncing') {
error('## Wont start to sync while status is %s', self.status);
return next();
}
@ -411,20 +438,19 @@ HistoricSync.prototype.start = function(opts, next) {
self.showProgress();
return self.status === 'syncing';
},
function (w_cb) {
self.getFn(function(err,blockInfo) {
function(w_cb) {
self.getFn(function(err, blockInfo) {
if (err) return w_cb(self.setError(err));
if (blockInfo && blockInfo.hash && (!opts.stopAt || opts.stopAt !== blockInfo.hash)) {
if (blockInfo && blockInfo.hash && (!opts.stopAt || opts.stopAt !== blockInfo.hash)) {
self.sync.storeTipBlock(blockInfo, self.allowReorgs, function(err, height) {
if (err) return w_cb(self.setError(err));
if (height>=0) self.height=height;
setImmediate(function(){
if (height >= 0) self.height = height;
setImmediate(function() {
return w_cb(err);
});
});
}
else {
} else {
self.endTs = Date.now();
self.status = 'finished';
var info = self.info();