diff --git a/lib/HistoricSync.js b/lib/HistoricSync.js index 636bb11..1a17c20 100644 --- a/lib/HistoricSync.js +++ b/lib/HistoricSync.js @@ -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,55 @@ 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); + + if (this.checkBitcoinCoreVersion) { + console.log('-------------------------------------------------------'); + console.log('- Bitcoin Core version is greater or equal than 10.99 -'); + console.log('-------------------------------------------------------'); + } + this.sync = new Sync(opts); - this.height =0; + this.height = 0; } +HistoricSync.prototype.checkBitcoinCoreVersion = function() { + var self = this; + self.rpc.getInfo(function(err, info) { + if (err) { + console.log('ERROR ', err); + process.exit(-1); + }; + return info.result.version >= 109900; + }); +}; + 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 +89,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 +118,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 +136,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 +155,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 +170,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 +194,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 +220,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 +246,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 +278,12 @@ HistoricSync.prototype.updateStartBlock = function(opts, next) { HistoricSync.prototype.prepareFileSync = function(opts, next) { var self = this; - if ( opts.forceRPC || !config.bitcoind.dataDir || + 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 +305,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 +329,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 +342,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 +354,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 +383,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 +429,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();