remove unneeded files
This commit is contained in:
parent
e1f0051c0f
commit
95e0e5a4f7
@ -1,300 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var imports = require('soop').imports();
|
||||
|
||||
var config = imports.config || require('../config/config');
|
||||
var bitcore = require('bitcore');
|
||||
var networks = bitcore.networks;
|
||||
var async = require('async');
|
||||
|
||||
var logger = require('./logger').logger;
|
||||
var d = logger.log;
|
||||
var info = logger.info;
|
||||
|
||||
|
||||
|
||||
var syncId = 0;
|
||||
|
||||
function Sync(opts) {
|
||||
this.id = syncId++;
|
||||
this.opts = opts || {};
|
||||
this.bDb = require('./BlockDb').default();
|
||||
this.txDb = require('./TransactionDb').default();
|
||||
this.network = config.network === 'testnet' ? networks.testnet : networks.livenet;
|
||||
this.cachedLastHash = null;
|
||||
}
|
||||
|
||||
Sync.prototype.close = function(cb) {
|
||||
var self = this;
|
||||
self.txDb.close(function() {
|
||||
self.bDb.close(cb);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Sync.prototype.destroy = function(next) {
|
||||
var self = this;
|
||||
async.series([
|
||||
|
||||
function(b) {
|
||||
self.bDb.drop(b);
|
||||
},
|
||||
function(b) {
|
||||
self.txDb.drop(b);
|
||||
},
|
||||
], next);
|
||||
};
|
||||
|
||||
/*
|
||||
* Arrives a NEW block, which is the new TIP
|
||||
*
|
||||
* Case 0) Simple case
|
||||
* A-B-C-D-E(TIP)-NEW
|
||||
*
|
||||
* Case 1)
|
||||
* A-B-C-D-E(TIP)
|
||||
* \
|
||||
* NEW
|
||||
*
|
||||
* 1) Declare D-E orphans (and possible invalidate TXs on them)
|
||||
*
|
||||
* Case 2)
|
||||
* A-B-C-D-E(TIP)
|
||||
* \
|
||||
* F-G-NEW
|
||||
* 1) Set F-G as connected (mark TXs as valid)
|
||||
* 2) Set new heights in F-G-NEW
|
||||
* 3) Declare D-E orphans (and possible invalidate TXs on them)
|
||||
*
|
||||
*
|
||||
* Case 3)
|
||||
*
|
||||
* A-B-C-D-E(TIP) ... NEW
|
||||
*
|
||||
* NEW is ignored (if allowReorgs is false)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
Sync.prototype.storeTipBlock = function(b, allowReorgs, cb) {
|
||||
|
||||
if (typeof allowReorgs === 'function') {
|
||||
cb = allowReorgs;
|
||||
allowReorgs = true;
|
||||
}
|
||||
if (!b) return cb();
|
||||
var self = this;
|
||||
|
||||
if ( self.storingBlock ) {
|
||||
logger.debug('Storing a block already. Delaying storeTipBlock with:' +
|
||||
b.hash);
|
||||
return setTimeout( function() {
|
||||
logger.debug('Retrying storeTipBlock with: ' + b.hash);
|
||||
self.storeTipBlock(b,allowReorgs,cb);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
self.storingBlock=1;
|
||||
var oldTip, oldNext, oldHeight, needReorg = false, height = -1;
|
||||
var newPrev = b.previousblockhash;
|
||||
async.series([
|
||||
|
||||
// This seems unnecesary.
|
||||
// function(c) {
|
||||
// // TODO? remove this check?
|
||||
// self.bDb.has(b.hash, function(err, val) {
|
||||
// return c(err ||
|
||||
// (val ? new Error('WARN: Ignoring already existing block:' + b.hash) : null));
|
||||
// });
|
||||
// },
|
||||
function(c) {
|
||||
if (!allowReorgs || newPrev === self.cachedLastHash) return c();
|
||||
self.bDb.has(newPrev, function(err, val) {
|
||||
// Genesis? no problem
|
||||
if (!val && newPrev.match(/^0+$/)) return c();
|
||||
return c(err ||
|
||||
(!val ? new Error('NEED_SYNC Ignoring block with non existing prev:' + b.hash) : null));
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
if (!allowReorgs) return c();
|
||||
self.bDb.getTip(function(err, hash, h) {
|
||||
oldTip = hash;
|
||||
oldHeight = hash ? (h || 0) : -1
|
||||
if (oldTip && newPrev !== oldTip) {
|
||||
needReorg = true;
|
||||
logger.debug('REORG Triggered, tip mismatch');
|
||||
}
|
||||
return c();
|
||||
});
|
||||
},
|
||||
|
||||
function(c) {
|
||||
if (!needReorg) return c();
|
||||
self.bDb.getNext(newPrev, function(err, val) {
|
||||
if (err) return c(err);
|
||||
oldNext = val;
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
if (!allowReorgs) return c();
|
||||
if (needReorg) {
|
||||
info('NEW TIP: %s NEED REORG (old tip: %s #%d)', b.hash, oldTip, oldHeight);
|
||||
self.processReorg(oldTip, oldNext, newPrev, oldHeight, function(err, h) {
|
||||
if (err) throw err;
|
||||
|
||||
height = h;
|
||||
return c();
|
||||
});
|
||||
}
|
||||
else {
|
||||
height = oldHeight + 1;
|
||||
return c();
|
||||
}
|
||||
},
|
||||
function(c) {
|
||||
self.cachedLastHash = b.hash; // just for speed up.
|
||||
self.bDb.add(b, height, c);
|
||||
},
|
||||
function(c) {
|
||||
if (!allowReorgs) return c();
|
||||
self.bDb.setTip(b.hash, height, function(err) {
|
||||
return c(err);
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
self.bDb.setNext(newPrev, b.hash, function(err) {
|
||||
return c(err);
|
||||
});
|
||||
}
|
||||
|
||||
],
|
||||
function(err) {
|
||||
if (err && err.toString().match(/WARN/)) {
|
||||
err = null;
|
||||
}
|
||||
self.storingBlock=0;
|
||||
return cb(err, height);
|
||||
});
|
||||
};
|
||||
|
||||
Sync.prototype.processReorg = function(oldTip, oldNext, newPrev, oldHeight, cb) {
|
||||
var self = this;
|
||||
|
||||
var orphanizeFrom, newHeight;
|
||||
|
||||
async.series([
|
||||
|
||||
function(c) {
|
||||
self.bDb.getHeight(newPrev, function(err, height) {
|
||||
if (!height) {
|
||||
// Case 3 + allowReorgs = true
|
||||
return c(new Error('Could not found block:' + newPrev));
|
||||
}
|
||||
if (height<0) return c();
|
||||
|
||||
newHeight = height + 1;
|
||||
info('Reorg Case 1) OldNext: %s NewHeight: %d', oldNext, newHeight);
|
||||
orphanizeFrom = oldNext;
|
||||
return c(err);
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
if (orphanizeFrom) return c();
|
||||
|
||||
info('Reorg Case 2)');
|
||||
self.setBranchConnectedBackwards(newPrev, function(err, yHash, newYHashNext, height) {
|
||||
if (err) return c(err);
|
||||
newHeight = height;
|
||||
self.bDb.getNext(yHash, function(err, yHashNext) {
|
||||
// Connect the new branch, and orphanize the old one.
|
||||
orphanizeFrom = yHashNext;
|
||||
self.bDb.setNext(yHash, newYHashNext, function(err) {
|
||||
return c(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
if (!orphanizeFrom) return c();
|
||||
self._setBranchOrphan(orphanizeFrom, function(err) {
|
||||
return c(err);
|
||||
});
|
||||
},
|
||||
],
|
||||
function(err) {
|
||||
return cb(err, newHeight);
|
||||
});
|
||||
};
|
||||
|
||||
Sync.prototype._setBranchOrphan = function(fromHash, cb) {
|
||||
var self = this,
|
||||
hashInterator = fromHash;
|
||||
|
||||
async.whilst(
|
||||
function() {
|
||||
return hashInterator;
|
||||
},
|
||||
function(c) {
|
||||
self.bDb.setBlockNotMain(hashInterator, function(err) {
|
||||
if (err) return cb(err);
|
||||
self.bDb.getNext(hashInterator, function(err, val) {
|
||||
hashInterator = val;
|
||||
return c(err);
|
||||
});
|
||||
});
|
||||
}, cb);
|
||||
};
|
||||
|
||||
Sync.prototype.setBranchConnectedBackwards = function(fromHash, cb) {
|
||||
//console.log('[Sync.js.219:setBranchConnectedBackwards:]',fromHash); //TODO
|
||||
var self = this,
|
||||
hashInterator = fromHash,
|
||||
lastHash = fromHash,
|
||||
yHeight,
|
||||
branch = [];
|
||||
|
||||
async.doWhilst(
|
||||
function(c) {
|
||||
branch.unshift(hashInterator);
|
||||
|
||||
self.bDb.getPrev(hashInterator, function(err, val) {
|
||||
if (err) return c(err);
|
||||
lastHash = hashInterator;
|
||||
hashInterator = val;
|
||||
self.bDb.getHeight(hashInterator, function(err, height) {
|
||||
yHeight = height;
|
||||
return c();
|
||||
});
|
||||
});
|
||||
},
|
||||
function() {
|
||||
return hashInterator && yHeight<=0;
|
||||
},
|
||||
function() {
|
||||
info('\tFound yBlock: %s #%d', hashInterator, yHeight);
|
||||
var heightIter = yHeight + 1;
|
||||
var hashIter;
|
||||
async.whilst(
|
||||
function() {
|
||||
hashIter = branch.shift();
|
||||
return hashIter;
|
||||
},
|
||||
function(c) {
|
||||
self.bDb.setBlockMain(hashIter, heightIter++, c);
|
||||
},
|
||||
function(err) {
|
||||
return cb(err, hashInterator, lastHash, heightIter);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//Store unconfirmed TXs
|
||||
Sync.prototype.storeTx = function(tx, cb) {
|
||||
this.txDb.add(tx, cb);
|
||||
};
|
||||
|
||||
|
||||
module.exports = require('soop')(Sync);
|
||||
@ -1,142 +0,0 @@
|
||||
'use strict';
|
||||
var bitcore = require('bitcore'),
|
||||
Block = bitcore.Block,
|
||||
networks = bitcore.networks,
|
||||
Parser = bitcore.BinaryParser,
|
||||
fs = require('fs'),
|
||||
Buffer = bitcore.Buffer,
|
||||
glob = require('glob'),
|
||||
async = require('async');
|
||||
|
||||
function BlockExtractor(dataDir, network) {
|
||||
var path = dataDir + '/blocks/blk*.dat';
|
||||
|
||||
this.dataDir = dataDir;
|
||||
this.files = glob.sync(path);
|
||||
this.nfiles = this.files.length;
|
||||
|
||||
if (this.nfiles === 0)
|
||||
throw new Error('Could not find block files at: ' + path);
|
||||
|
||||
this.currentFileIndex = 0;
|
||||
this.isCurrentRead = false;
|
||||
this.currentBuffer = null;
|
||||
this.currentParser = null;
|
||||
this.network = network === 'testnet' ? networks.testnet: networks.livenet;
|
||||
this.magic = this.network.magic.toString('hex');
|
||||
}
|
||||
|
||||
BlockExtractor.prototype.currentFile = function() {
|
||||
return this.files[this.currentFileIndex];
|
||||
};
|
||||
|
||||
|
||||
BlockExtractor.prototype.nextFile = function() {
|
||||
if (this.currentFileIndex < 0) return false;
|
||||
|
||||
var ret = true;
|
||||
|
||||
this.isCurrentRead = false;
|
||||
this.currentBuffer = null;
|
||||
this.currentParser = null;
|
||||
|
||||
if (this.currentFileIndex < this.nfiles - 1) {
|
||||
this.currentFileIndex++;
|
||||
}
|
||||
else {
|
||||
this.currentFileIndex=-1;
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
BlockExtractor.prototype.readCurrentFileSync = function() {
|
||||
if (this.currentFileIndex < 0 || this.isCurrentRead) return;
|
||||
|
||||
this.isCurrentRead = true;
|
||||
|
||||
var fname = this.currentFile();
|
||||
if (!fname) return;
|
||||
|
||||
|
||||
var stats = fs.statSync(fname);
|
||||
|
||||
var size = stats.size;
|
||||
|
||||
console.log('Reading Blockfile %s [%d MB]',
|
||||
fname, parseInt(size/1024/1024));
|
||||
|
||||
var fd = fs.openSync(fname, 'r');
|
||||
|
||||
var buffer = new Buffer(size);
|
||||
|
||||
fs.readSync(fd, buffer, 0, size, 0);
|
||||
|
||||
this.currentBuffer = buffer;
|
||||
this.currentParser = new Parser(buffer);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
BlockExtractor.prototype._getMagic = function() {
|
||||
if (!this.currentParser)
|
||||
return null;
|
||||
|
||||
var byte0 = this.currentParser ? this.currentParser.buffer(1).toString('hex') : null;
|
||||
|
||||
|
||||
|
||||
// Grab 3 bytes from block without removing them
|
||||
var p = this.currentParser.pos;
|
||||
var bytes123 = this.currentParser.subject.toString('hex',p,p+3);
|
||||
var magic = byte0 + bytes123;
|
||||
|
||||
if (magic !=='00000000' && magic !== this.magic) {
|
||||
if(this.errorCount++ > 4)
|
||||
throw new Error('CRITICAL ERROR: Magic number mismatch: ' +
|
||||
magic + '!=' + this.magic);
|
||||
magic=null;
|
||||
}
|
||||
|
||||
if (magic==='00000000')
|
||||
magic =null;
|
||||
|
||||
return magic;
|
||||
};
|
||||
|
||||
BlockExtractor.prototype.getNextBlock = function(cb) {
|
||||
var b;
|
||||
var magic;
|
||||
var isFinished = 0;
|
||||
|
||||
while(!magic && !isFinished) {
|
||||
this.readCurrentFileSync();
|
||||
magic= this._getMagic();
|
||||
|
||||
if (!this.currentParser || this.currentParser.eof() ) {
|
||||
|
||||
if (this.nextFile()) {
|
||||
console.log('Moving forward to file:' + this.currentFile() );
|
||||
magic = null;
|
||||
} else {
|
||||
console.log('Finished all files');
|
||||
isFinished = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isFinished)
|
||||
return cb();
|
||||
|
||||
// Remove 3 bytes from magic and spacer
|
||||
this.currentParser.buffer(3+4);
|
||||
|
||||
b = new Block();
|
||||
b.parse(this.currentParser);
|
||||
b.getHash();
|
||||
this.errorCount=0;
|
||||
return cb(null,b);
|
||||
};
|
||||
|
||||
module.exports = require('soop')(BlockExtractor);
|
||||
|
||||
@ -1,435 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
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 BlockExtractor = require('./BlockExtractor.js');
|
||||
var buffertools = require('buffertools');
|
||||
var bitcoreUtil = bitcore.util;
|
||||
var logger = require('./logger').logger;
|
||||
var info = logger.info;
|
||||
var error = logger.error;
|
||||
var PERCENTAGE_TO_START_FROM_RPC = 0.96;
|
||||
|
||||
var BAD_GEN_ERROR = 'Bad genesis block. Network mismatch between bitcore-node and bitcoind? bitcore-node is configured for:';
|
||||
var BAD_GEN_ERROR_DB = 'Bad genesis block. Network mismatch between bitcore-node and levelDB? bitcore-node is configured for:';
|
||||
|
||||
function HistoricSync(opts) {
|
||||
opts = opts || {};
|
||||
this.shouldBroadcast = opts.shouldBroadcastSync;
|
||||
|
||||
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;
|
||||
|
||||
this.rpc = new RpcClient(config.bitcoind);
|
||||
this.sync = new Sync(opts);
|
||||
this.height =0;
|
||||
}
|
||||
|
||||
HistoricSync.prototype.showProgress = function() {
|
||||
var self = this;
|
||||
|
||||
if ( self.status ==='syncing' &&
|
||||
( self.height ) % self.step !== 1) return;
|
||||
|
||||
if (self.error)
|
||||
error(self.error);
|
||||
|
||||
else {
|
||||
self.updatePercentage();
|
||||
info(util.format('status: [%d%%]', self.syncPercentage));
|
||||
}
|
||||
if (self.shouldBroadcast) {
|
||||
sockets.broadcastSyncInfo(self.info());
|
||||
}
|
||||
//
|
||||
// if (self.syncPercentage > 10) {
|
||||
// process.exit(-1);
|
||||
// }
|
||||
};
|
||||
|
||||
|
||||
HistoricSync.prototype.setError = function(err) {
|
||||
var self = this;
|
||||
self.error = err.message?err.message:err.toString();
|
||||
self.status='error';
|
||||
self.showProgress();
|
||||
return err;
|
||||
};
|
||||
|
||||
|
||||
|
||||
HistoricSync.prototype.close = function() {
|
||||
this.sync.close();
|
||||
};
|
||||
|
||||
|
||||
HistoricSync.prototype.info = function() {
|
||||
this.updatePercentage();
|
||||
return {
|
||||
status: this.status,
|
||||
blockChainHeight: this.blockChainHeight,
|
||||
syncPercentage: this.syncPercentage,
|
||||
height: this.height,
|
||||
syncTipHash: this.sync.tip,
|
||||
error: this.error,
|
||||
type: this.type,
|
||||
startTs: this.startTs,
|
||||
endTs: this.endTs,
|
||||
};
|
||||
};
|
||||
|
||||
HistoricSync.prototype.updatePercentage = function() {
|
||||
var r = this.height / this.blockChainHeight;
|
||||
this.syncPercentage = parseFloat(100 * r).toFixed(3);
|
||||
if (this.syncPercentage > 100) this.syncPercentage = 100;
|
||||
};
|
||||
|
||||
HistoricSync.prototype.getBlockFromRPC = function(cb) {
|
||||
var self = this;
|
||||
|
||||
if (!self.currentRpcHash) return cb();
|
||||
|
||||
var blockInfo;
|
||||
self.rpc.getBlock(self.currentRpcHash, function(err, ret) {
|
||||
if (err) return cb(err);
|
||||
if (ret) {
|
||||
blockInfo = ret.result;
|
||||
// this is to match block retreived from file
|
||||
if (blockInfo.hash === self.genesis)
|
||||
blockInfo.previousblockhash =
|
||||
self.network.genesisBlock.prev_hash.toString('hex');
|
||||
|
||||
self.currentRpcHash = blockInfo.nextblockhash;
|
||||
}
|
||||
else {
|
||||
blockInfo = null;
|
||||
}
|
||||
return cb(null, blockInfo);
|
||||
});
|
||||
};
|
||||
|
||||
HistoricSync.prototype.getStandardizedBlock = function(b) {
|
||||
var self = this;
|
||||
|
||||
var block = {
|
||||
hash: bitcoreUtil.formatHashFull(b.getHash()),
|
||||
previousblockhash: bitcoreUtil.formatHashFull(b.prev_hash),
|
||||
time: b.timestamp,
|
||||
};
|
||||
var isCoinBase = 1;
|
||||
block.tx = b.txs.map(function(tx){
|
||||
var ret = self.sync.txDb.getStandardizedTx(tx, b.timestamp, isCoinBase);
|
||||
isCoinBase=0;
|
||||
return ret;
|
||||
});
|
||||
return block;
|
||||
};
|
||||
|
||||
HistoricSync.prototype.getBlockFromFile = function(cb) {
|
||||
var self = this;
|
||||
|
||||
var blockInfo;
|
||||
|
||||
//get Info
|
||||
self.blockExtractor.getNextBlock(function(err, b) {
|
||||
if (err || ! b) return cb(err);
|
||||
blockInfo = self.getStandardizedBlock(b);
|
||||
self.sync.bDb.setLastFileIndex(self.blockExtractor.currentFileIndex, function(err) {
|
||||
return cb(err,blockInfo);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
HistoricSync.prototype.updateBlockChainHeight = function(cb) {
|
||||
var self = this;
|
||||
|
||||
self.rpc.getBlockCount(function(err, res) {
|
||||
self.blockChainHeight = res.result;
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
HistoricSync.prototype.checkNetworkSettings = function(next) {
|
||||
var self = this;
|
||||
|
||||
self.hasGenesis = false;
|
||||
|
||||
// check network config
|
||||
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)) {
|
||||
err = new Error(BAD_GEN_ERROR_DB + config.network);
|
||||
}
|
||||
self.hasGenesis = b?true:false;
|
||||
return next(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
HistoricSync.prototype.updateStartBlock = function(opts, next) {
|
||||
var self = this;
|
||||
|
||||
self.startBlock = self.genesis;
|
||||
|
||||
if (opts.startAt) {
|
||||
self.sync.bDb.fromHashWithInfo(opts.startAt, function(err, bi) {
|
||||
var blockInfo = bi ? bi.info : {};
|
||||
if (blockInfo.height) {
|
||||
self.startBlock = opts.startAt;
|
||||
self.height = blockInfo.height;
|
||||
info('Resuming sync from block: %s #%d',opts.startAt, self.height);
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.sync.bDb.getTip(function(err,tip, height) {
|
||||
if (!tip) return next();
|
||||
|
||||
var blockInfo;
|
||||
var oldtip;
|
||||
|
||||
//check that the tip is still on the mainchain
|
||||
async.doWhilst(
|
||||
function(cb) {
|
||||
self.sync.bDb.fromHashWithInfo(tip, function(err, bi) {
|
||||
blockInfo = bi ? bi.info : {};
|
||||
if (oldtip)
|
||||
self.sync.bDb.setBlockNotMain(oldtip, cb);
|
||||
else
|
||||
return cb();
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
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);
|
||||
process.exit(1);
|
||||
}
|
||||
if ( self.blockChainHeight === blockInfo.height ||
|
||||
blockInfo.confirmations > 0) {
|
||||
ret = false;
|
||||
}
|
||||
else {
|
||||
oldtip = tip;
|
||||
if (!tip)
|
||||
throw new Error('Previous blockchain tip was not found on bitcoind. Please reset bitcore-node DB. Tip was:'+tip)
|
||||
tip = blockInfo.previousblockhash;
|
||||
info('Previous TIP is now orphan. Back to:' + tip);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
function(err) {
|
||||
self.startBlock = tip;
|
||||
self.height = height;
|
||||
info('Resuming sync from block: %s #%d',tip,height);
|
||||
return next(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
HistoricSync.prototype.prepareFileSync = function(opts, next) {
|
||||
var self = this;
|
||||
|
||||
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);
|
||||
} catch (e) {
|
||||
info(e.message + '. Disabling file sync.');
|
||||
return next();
|
||||
}
|
||||
|
||||
self.getFn = self.getBlockFromFile;
|
||||
self.allowReorgs = true;
|
||||
self.sync.bDb.getLastFileIndex(function(err, idx) {
|
||||
|
||||
if (opts.forceStartFile)
|
||||
self.blockExtractor.currentFileIndex = opts.forceStartFile;
|
||||
else if (idx) self.blockExtractor.currentFileIndex = idx;
|
||||
|
||||
var h = self.genesis;
|
||||
|
||||
info('Seeking file to:' + self.startBlock);
|
||||
//forward till startBlock
|
||||
async.whilst(
|
||||
function() {
|
||||
return h !== self.startBlock;
|
||||
},
|
||||
function (w_cb) {
|
||||
self.getBlockFromFile(function(err,b) {
|
||||
if (!b) return w_cb('Could not find block ' + self.startBlock);
|
||||
h=b.hash;
|
||||
setImmediate(function(){
|
||||
return w_cb(err);
|
||||
});
|
||||
});
|
||||
}, function(err){
|
||||
console.log('\tFOUND Starting Block!');
|
||||
|
||||
// TODO SET HEIGHT
|
||||
return next(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
//NOP
|
||||
HistoricSync.prototype.prepareRpcSync = function(opts, next) {
|
||||
var self = this;
|
||||
|
||||
if (self.blockExtractor) return next();
|
||||
self.getFn = self.getBlockFromRPC;
|
||||
self.allowReorgs = true;
|
||||
self.currentRpcHash = self.startBlock;
|
||||
return next();
|
||||
};
|
||||
|
||||
HistoricSync.prototype.showSyncStartMessage = function() {
|
||||
var self = this;
|
||||
|
||||
info('Got ' + self.height +
|
||||
' blocks in current DB, out of ' + self.blockChainHeight + ' block at bitcoind');
|
||||
|
||||
if (self.blockExtractor) {
|
||||
info('bitcoind dataDir configured...importing blocks from .dat files');
|
||||
info('First file index: ' + self.blockExtractor.currentFileIndex);
|
||||
}
|
||||
else {
|
||||
info('syncing from RPC (slow)');
|
||||
}
|
||||
|
||||
info('Starting from: ', self.startBlock);
|
||||
self.showProgress();
|
||||
};
|
||||
|
||||
|
||||
HistoricSync.prototype.setupSyncStatus = function() {
|
||||
var self = this;
|
||||
|
||||
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.status = 'syncing';
|
||||
self.startTs = Date.now();
|
||||
self.endTs = null;
|
||||
this.error = null;
|
||||
this.syncPercentage = 0;
|
||||
};
|
||||
|
||||
HistoricSync.prototype.checkDBVersion = function(cb) {
|
||||
this.sync.txDb.checkVersion02(function(isOk){
|
||||
if (!isOk) {
|
||||
console.log('\n#############################\n\n ## bitcore-node API DB is older that v0.2. Please resync using:\n $ util/sync.js -D\n More information at bitcore-node API\'s Readme.md');
|
||||
process.exit(1);
|
||||
}
|
||||
// Add more test here in future changes.
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
HistoricSync.prototype.prepareToSync = function(opts, next) {
|
||||
var self = this;
|
||||
|
||||
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();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
HistoricSync.prototype.start = function(opts, next) {
|
||||
var self = this;
|
||||
|
||||
if (self.status==='starting' || self.status==='syncing') {
|
||||
error('## Wont start to sync while status is %s', self.status);
|
||||
return next();
|
||||
}
|
||||
|
||||
self.prepareToSync(opts, function(err) {
|
||||
if (err) return next(self.setError(err));
|
||||
|
||||
async.whilst(
|
||||
function() {
|
||||
self.showProgress();
|
||||
return self.status === 'syncing';
|
||||
},
|
||||
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)) {
|
||||
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(){
|
||||
return w_cb(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.endTs = Date.now();
|
||||
self.status = 'finished';
|
||||
var info = self.info();
|
||||
logger.debug('Done Syncing blockchain', info.type, 'to height', info.height);
|
||||
return w_cb(err);
|
||||
}
|
||||
});
|
||||
}, next);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = require('soop')(HistoricSync);
|
||||
@ -1,150 +0,0 @@
|
||||
'use strict';
|
||||
var fs = require('fs');
|
||||
var bitcore = require('bitcore');
|
||||
var bitcoreUtil = bitcore.util;
|
||||
var Sync = require('./Sync');
|
||||
var Peer = bitcore.Peer;
|
||||
var PeerManager = bitcore.PeerManager;
|
||||
var config = require('../config/config');
|
||||
var networks = bitcore.networks;
|
||||
var sockets = require('../app/controllers/socket.js');
|
||||
|
||||
var peerdb_fn = 'peerdb.json';
|
||||
|
||||
function PeerSync(opts) {
|
||||
opts = opts|| {};
|
||||
this.shouldBroadcast = opts.shouldBroadcast;
|
||||
this.connected = false;
|
||||
this.peerdb = undefined;
|
||||
this.allowReorgs = false;
|
||||
var pmConfig = {
|
||||
network: config.network
|
||||
};
|
||||
this.peerman = new PeerManager(pmConfig);
|
||||
this.load_peers();
|
||||
this.sync = new Sync(opts);
|
||||
this.verbose = opts.verbose || false;
|
||||
}
|
||||
|
||||
PeerSync.prototype.log = function() {
|
||||
if (this.verbose) console.log(arguments);
|
||||
};
|
||||
|
||||
PeerSync.prototype.load_peers = function() {
|
||||
this.peerdb = [{
|
||||
ipv4: config.bitcoind.p2pHost,
|
||||
port: config.bitcoind.p2pPort
|
||||
}];
|
||||
|
||||
fs.writeFileSync(peerdb_fn, JSON.stringify(this.peerdb));
|
||||
};
|
||||
|
||||
PeerSync.prototype.info = function() {
|
||||
return {
|
||||
connected: this.connected,
|
||||
host: this.peerdb[0].ipv4,
|
||||
port: this.peerdb[0].port
|
||||
};
|
||||
};
|
||||
|
||||
PeerSync.prototype.handleInv = function(info) {
|
||||
var invs = info.message.invs;
|
||||
info.conn.sendGetData(invs);
|
||||
};
|
||||
|
||||
PeerSync.prototype._broadcastAddr = function(txid, addrs) {
|
||||
if (addrs) {
|
||||
for(var ii in addrs){
|
||||
sockets.broadcastAddressTx(txid, ii);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
PeerSync.prototype.handleTx = function(info) {
|
||||
var self =this;
|
||||
var tx = this.sync.txDb.getStandardizedTx(info.message.tx);
|
||||
self.log('[p2p_sync] Handle tx: ' + tx.txid);
|
||||
tx.time = tx.time || Math.round(new Date().getTime() / 1000);
|
||||
|
||||
this.sync.storeTx(tx, function(err, relatedAddrs) {
|
||||
if (err) {
|
||||
self.log('[p2p_sync] Error in handle TX: ' + JSON.stringify(err));
|
||||
}
|
||||
else if (self.shouldBroadcast) {
|
||||
sockets.broadcastTx(tx);
|
||||
self._broadcastAddr(tx.txid, relatedAddrs);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
PeerSync.prototype.handleBlock = function(info) {
|
||||
var self = this;
|
||||
var block = info.message.block;
|
||||
var blockHash = bitcoreUtil.formatHashFull(block.calcHash());
|
||||
self.log('[p2p_sync] Handle block: %s (allowReorgs: %s)', blockHash, self.allowReorgs);
|
||||
|
||||
var tx_hashes = block.txs.map(function(tx) {
|
||||
return bitcoreUtil.formatHashFull(tx.hash);
|
||||
});
|
||||
|
||||
self.sync.storeTipBlock({
|
||||
'hash': blockHash,
|
||||
'tx': tx_hashes,
|
||||
'previousblockhash': bitcoreUtil.formatHashFull(block.prev_hash),
|
||||
}, self.allowReorgs, function(err, height) {
|
||||
if (err && err.message.match(/NEED_SYNC/) && self.historicSync) {
|
||||
self.log('[p2p_sync] Orphan block received. Triggering sync');
|
||||
self.historicSync.start({forceRPC:1}, function(){
|
||||
self.log('[p2p_sync] Done resync.');
|
||||
});
|
||||
}
|
||||
else if (err) {
|
||||
self.log('[p2p_sync] Error in handle Block: ', err);
|
||||
}
|
||||
else {
|
||||
if (self.shouldBroadcast) {
|
||||
sockets.broadcastBlock(blockHash);
|
||||
// broadcasting address here is a bad idea. listening to new block
|
||||
// should be enoght
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
PeerSync.prototype.handleConnected = function(data) {
|
||||
var peerman = data.pm;
|
||||
var peers_n = peerman.peers.length;
|
||||
this.log('[p2p_sync] Connected to ' + peers_n + ' peer' + (peers_n !== 1 ? 's' : ''));
|
||||
};
|
||||
|
||||
PeerSync.prototype.run = function() {
|
||||
var self = this;
|
||||
|
||||
this.peerdb.forEach(function(datum) {
|
||||
var peer = new Peer(datum.ipv4, datum.port);
|
||||
self.peerman.addPeer(peer);
|
||||
});
|
||||
|
||||
this.peerman.on('connection', function(conn) {
|
||||
self.connected = true;
|
||||
conn.on('inv', self.handleInv.bind(self));
|
||||
conn.on('block', self.handleBlock.bind(self));
|
||||
conn.on('tx', self.handleTx.bind(self));
|
||||
});
|
||||
this.peerman.on('connect', self.handleConnected.bind(self));
|
||||
|
||||
this.peerman.on('netDisconnected', function() {
|
||||
self.connected = false;
|
||||
});
|
||||
|
||||
this.peerman.start();
|
||||
};
|
||||
|
||||
PeerSync.prototype.close = function() {
|
||||
this.sync.close();
|
||||
};
|
||||
|
||||
|
||||
module.exports = require('soop')(PeerSync);
|
||||
73
ws/index.js
73
ws/index.js
@ -1,73 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// server-side socket behaviour
|
||||
var ios = null; // io is already taken in express
|
||||
var util = require('bitcore').util;
|
||||
var logger = require('../../lib/logger').logger;
|
||||
|
||||
module.exports.init = function(io_ext) {
|
||||
ios = io_ext;
|
||||
if (ios) {
|
||||
// when a new socket connects
|
||||
ios.sockets.on('connection', function(socket) {
|
||||
logger.verbose('New connection from ' + socket.id);
|
||||
// when it subscribes, make it join the according room
|
||||
socket.on('subscribe', function(topic) {
|
||||
logger.debug('subscribe to ' + topic);
|
||||
socket.join(topic);
|
||||
socket.emit('subscribed');
|
||||
});
|
||||
|
||||
// disconnect handler
|
||||
socket.on('disconnect', function() {
|
||||
logger.verbose('disconnected ' + socket.id);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
return ios;
|
||||
};
|
||||
|
||||
var simpleTx = function(tx) {
|
||||
return {
|
||||
txid: tx
|
||||
};
|
||||
};
|
||||
|
||||
var fullTx = function(tx) {
|
||||
var t = {
|
||||
txid: tx.txid,
|
||||
size: tx.size,
|
||||
};
|
||||
// Outputs
|
||||
var valueOut = 0;
|
||||
tx.vout.forEach(function(o) {
|
||||
valueOut += o.valueSat;
|
||||
});
|
||||
|
||||
t.valueOut = (valueOut.toFixed(8) / util.COIN);
|
||||
return t;
|
||||
};
|
||||
|
||||
module.exports.broadcastTx = function(tx) {
|
||||
if (ios) {
|
||||
var t = (typeof tx === 'string') ? simpleTx(tx) : fullTx(tx);
|
||||
ios.sockets.in('inv').emit('tx', t);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.broadcastBlock = function(block) {
|
||||
if (ios)
|
||||
ios.sockets.in('inv').emit('block', block);
|
||||
};
|
||||
|
||||
module.exports.broadcastAddressTx = function(txid, address) {
|
||||
if (ios) {
|
||||
ios.sockets.in(address).emit(address, txid);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.broadcastSyncInfo = function(historicSync) {
|
||||
if (ios)
|
||||
ios.sockets.in('sync').emit('status', historicSync);
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user