refactor Rpc classes. add file index in DB
This commit is contained in:
parent
5cd43cbcaa
commit
ab808e5c2b
|
@ -5,23 +5,21 @@ require('classtool');
|
||||||
|
|
||||||
function spec(b) {
|
function spec(b) {
|
||||||
|
|
||||||
var TIMESTAMP_PREFIX = 'bts-'; // b-ts-<ts> => <hash>
|
var TIMESTAMP_PREFIX = 'bts-'; // b-ts-<ts> => <hash>
|
||||||
var PREV_PREFIX = 'bpr-'; // b-prev-<hash> => <prev_hash>
|
var PREV_PREFIX = 'bpr-'; // b-prev-<hash> => <prev_hash>
|
||||||
var NEXT_PREFIX = 'bne-'; // b-next-<hash> => <next_hash>
|
var NEXT_PREFIX = 'bne-'; // b-next-<hash> => <next_hash>
|
||||||
var MAIN_PREFIX = 'bma-'; // b-main-<hash> => 1/0
|
var MAIN_PREFIX = 'bma-'; // b-main-<hash> => 1/0
|
||||||
var TIP = 'bti-'; // last block on the chain
|
var TIP = 'bti-'; // last block on the chain
|
||||||
|
var LAST_FILE_INDEX = 'file-'; // last processed file index
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
var RpcClient = require('bitcore/RpcClient').class(),
|
var levelup = require('levelup'),
|
||||||
util = require('bitcore/util/util'),
|
|
||||||
levelup = require('levelup'),
|
|
||||||
BitcoreBlock= require('bitcore/Block').class(),
|
|
||||||
config = require('../config/config');
|
config = require('../config/config');
|
||||||
var db = b.db || levelup(config.leveldb + '/blocks');
|
var db = b.db || levelup(config.leveldb + '/blocks');
|
||||||
var rpc = b.rpc || new RpcClient(config.bitcoind);
|
var Rpc = b.rpc || require('./Rpc').class();
|
||||||
|
|
||||||
var BlockDb = function() {
|
var BlockDb = function() {
|
||||||
};
|
};
|
||||||
|
@ -80,6 +78,24 @@ function spec(b) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
BlockDb.prototype.setLastFileIndex = function(idx, cb) {
|
||||||
|
var self = this;
|
||||||
|
if (this.lastFileIndexSaved === idx) return cb();
|
||||||
|
|
||||||
|
db.put(LAST_FILE_INDEX, idx, function(err) {
|
||||||
|
self.lastFileIndexSaved = idx;
|
||||||
|
return cb(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
BlockDb.prototype.getLastFileIndex = function(cb) {
|
||||||
|
db.get(LAST_FILE_INDEX, function(err,val) {
|
||||||
|
if (err && err.notFound) { err = null; val = null;}
|
||||||
|
return cb(err,val);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
BlockDb.prototype.getNext = function(hash, cb) {
|
BlockDb.prototype.getNext = function(hash, cb) {
|
||||||
db.get(NEXT_PREFIX + hash, function(err,val) {
|
db.get(NEXT_PREFIX + hash, function(err,val) {
|
||||||
if (err && err.notFound) { err = null; val = null;}
|
if (err && err.notFound) { err = null; val = null;}
|
||||||
|
@ -138,13 +154,8 @@ function spec(b) {
|
||||||
BlockDb.prototype.fromHashWithInfo = function(hash, cb) {
|
BlockDb.prototype.fromHashWithInfo = function(hash, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
rpc.getBlock(hash, function(err, info) {
|
Rpc.getBlock(hash, function(err, info) {
|
||||||
// Not found?
|
if (err || !info) return cb(err);
|
||||||
if (err && err.code === -5) return cb();
|
|
||||||
if (err) return cb(err);
|
|
||||||
|
|
||||||
if (info.result.height)
|
|
||||||
info.result.reward = BitcoreBlock.getBlockValue(info.result.height) / util.COIN ;
|
|
||||||
|
|
||||||
self.isMain(hash, function(err, val) {
|
self.isMain(hash, function(err, val) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
@ -182,12 +193,7 @@ function spec(b) {
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockDb.prototype.blockIndex = function(height, cb) {
|
BlockDb.prototype.blockIndex = function(height, cb) {
|
||||||
var rpc = new RpcClient(config.bitcoind);
|
return Rpc.blockIndex(height,cb);
|
||||||
rpc.getBlockHash(height, function(err, bh){
|
|
||||||
if (err) return cb(err);
|
|
||||||
|
|
||||||
cb(null, { blockHash: bh.result });
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return BlockDb;
|
return BlockDb;
|
||||||
|
|
|
@ -123,10 +123,9 @@ function spec() {
|
||||||
sockets.broadcastSyncInfo(self.info());
|
sockets.broadcastSyncInfo(self.info());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
// if (self.syncPercentage > 10) {
|
||||||
// if (self.syncPercentage > 10) {
|
// process.exit(-1);
|
||||||
// process.exit(-1);
|
// }
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
HistoricSync.prototype.getPrevNextBlock = function(blockHash, blockEnd, scanOpts, cb) {
|
HistoricSync.prototype.getPrevNextBlock = function(blockHash, blockEnd, scanOpts, cb) {
|
||||||
|
@ -277,19 +276,24 @@ function spec() {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sync.storeTipBlock(blockInfo, function(err) {
|
self.sync.storeTipBlock(blockInfo, function(err) {
|
||||||
if (blockInfo && blockInfo.hash) {
|
|
||||||
self.syncedBlocks++;
|
|
||||||
} else
|
|
||||||
self.status = 'finished';
|
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]',
|
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]',
|
||||||
blockInfo ? blockInfo.hash : '-', err, self.syncedBlocks));
|
blockInfo ? blockInfo.hash : '-', err, self.syncedBlocks));
|
||||||
|
return cb(err);
|
||||||
}
|
}
|
||||||
return cb(err);
|
|
||||||
|
self.sync.bDb.setLastFileIndex(self.blockExtractor.currentFileIndex, function(err) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
if (blockInfo && blockInfo.hash) {
|
||||||
|
self.syncedBlocks++;
|
||||||
|
} else
|
||||||
|
self.status = 'finished';
|
||||||
|
|
||||||
|
return cb(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -307,7 +311,7 @@ function spec() {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
HistoricSync.prototype.getBlockCount = function(cb) {
|
HistoricSync.prototype.updateBlockCount = function(cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (self.blockChainHeight) return cb();
|
if (self.blockChainHeight) return cb();
|
||||||
|
@ -333,8 +337,9 @@ function spec() {
|
||||||
}
|
}
|
||||||
return cb();
|
return cb();
|
||||||
},
|
},
|
||||||
// We are not using getBestBlockHash, because is not available in all clients
|
function (cb) {
|
||||||
function (cb) { return self.getBlockCount(cb); },
|
return self.updateBlockCount(cb);
|
||||||
|
},
|
||||||
function(cb) {
|
function(cb) {
|
||||||
if (!scanOpts.reverse) return cb();
|
if (!scanOpts.reverse) return cb();
|
||||||
self.rpc.getBlockHash(self.blockChainHeight, function(err, res) {
|
self.rpc.getBlockHash(self.blockChainHeight, function(err, res) {
|
||||||
|
@ -372,8 +377,6 @@ function spec() {
|
||||||
self.setError(err);
|
self.setError(err);
|
||||||
return next(err, 0);
|
return next(err, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SETUP Sync params
|
// SETUP Sync params
|
||||||
var start, end;
|
var start, end;
|
||||||
|
|
||||||
|
@ -432,42 +435,66 @@ function spec() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// upto if we have genesis block?
|
|
||||||
HistoricSync.prototype.smartImport = function(scanOpts, next) {
|
HistoricSync.prototype.smartImport = function(scanOpts, next) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.sync.bDb.has(self.genesis, function(err, b) {
|
var genesis, count;
|
||||||
if (err) return next(err);
|
async.series([
|
||||||
self.countNotOrphan(function(err, count) {
|
function(s_c) {
|
||||||
if (err) return next(err);
|
self.sync.bDb.has(self.genesis, function(err, b) {
|
||||||
self.getBlockCount(function(err) {
|
genesis = b;
|
||||||
if (err) return next(err);
|
return s_c(err);
|
||||||
|
|
||||||
if (!b || scanOpts.destroy || count < self.blockChainHeight * 0.8 ) {
|
|
||||||
|
|
||||||
if (!b)
|
|
||||||
p('Could not find Genesis block. Running FULL SYNC');
|
|
||||||
else
|
|
||||||
p('Less that 80% of current blockchain is stored. Running FULL SYNC',
|
|
||||||
parseInt(count/self.blockChainHeight*100));
|
|
||||||
|
|
||||||
if (config.bitcoind.dataDir) {
|
|
||||||
p('bitcoind dataDir configured...importing blocks from .dat files');
|
|
||||||
scanOpts.fromFiles = true;
|
|
||||||
self.blockExtractor = new BlockExtractor(config.bitcoind.dataDir, config.network);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
scanOpts.reverse = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
p('Genesis block found. Syncing upto old TIP.');
|
|
||||||
p('Got ' + count + ' out of ' + self.blockChainHeight + ' blocks');
|
|
||||||
scanOpts.reverse = true;
|
|
||||||
}
|
|
||||||
return self.importHistory(scanOpts, next);
|
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
|
function(s_c) {
|
||||||
|
if (scanOpts.destroy) return s_c();
|
||||||
|
|
||||||
|
self.countNotOrphan(function(err, c) {
|
||||||
|
count = c;
|
||||||
|
return s_c(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(s_c) {
|
||||||
|
if (!config.bitcoind.dataDir) return s_c();
|
||||||
|
|
||||||
|
self.sync.bDb.getLastFileIndex(function(err, idx) {
|
||||||
|
self.blockExtractor = new BlockExtractor(config.bitcoind.dataDir, config.network);
|
||||||
|
if (idx) self.blockExtractor.currentFileIndex = idx;
|
||||||
|
return s_c(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(s_c) {
|
||||||
|
self.updateBlockCount(s_c);
|
||||||
|
}],
|
||||||
|
function(err) {
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
|
if (!genesis || scanOpts.destroy || count < self.blockChainHeight * 0.9 ) {
|
||||||
|
|
||||||
|
// Full sync.
|
||||||
|
|
||||||
|
if (!genesis)
|
||||||
|
p('Could not find Genesis block. Running FULL SYNC');
|
||||||
|
else
|
||||||
|
p('Less that 90% of current blockchain is stored. Running FULL SYNC',
|
||||||
|
parseInt(count/self.blockChainHeight*100));
|
||||||
|
|
||||||
|
if (config.bitcoind.dataDir) {
|
||||||
|
p('bitcoind dataDir configured...importing blocks from .dat files');
|
||||||
|
p('Starting from file: ' + self.blockExtractor.currentFileIndex);
|
||||||
|
scanOpts.fromFiles = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scanOpts.reverse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p('Genesis block found. Syncing upto old TIP.');
|
||||||
|
p('Got ' + count + ' out of ' + self.blockChainHeight + ' blocks');
|
||||||
|
scanOpts.reverse = true;
|
||||||
|
}
|
||||||
|
return self.importHistory(scanOpts, next);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
require('classtool');
|
||||||
|
|
||||||
|
|
||||||
|
function spec(b) {
|
||||||
|
var RpcClient = require('bitcore/RpcClient').class(),
|
||||||
|
BitcoreTransaction = require('bitcore/Transaction').class(),
|
||||||
|
BitcoreBlock = require('bitcore/Block').class(),
|
||||||
|
bitcoreUtil = require('bitcore/util/util'),
|
||||||
|
util = require('util'),
|
||||||
|
config = require('../config/config');
|
||||||
|
|
||||||
|
var bitcoreRpc = b.bitcoreRpc || new RpcClient(config.bitcoind);
|
||||||
|
|
||||||
|
function Rpc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Rpc._parseRpcResult = function(info) {
|
||||||
|
var b = new Buffer(info.hex,'hex');
|
||||||
|
var tx = new BitcoreTransaction();
|
||||||
|
tx.parse(b);
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
if (tx.isCoinBase()) {
|
||||||
|
info.isCoinBase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var n =0;
|
||||||
|
info.vin.forEach(function(i) {
|
||||||
|
i.n = n++;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Outputs
|
||||||
|
var valueOutSat = 0;
|
||||||
|
info.vout.forEach( function(o) {
|
||||||
|
valueOutSat += o.value * bitcoreUtil.COIN;
|
||||||
|
});
|
||||||
|
info.valueOut = parseInt(valueOutSat) / bitcoreUtil.COIN;
|
||||||
|
info.size = b.length;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Rpc.errMsg = function(err) {
|
||||||
|
var e = err;
|
||||||
|
e.message += util.format(' [Host: %s:%d User:%s Using password:%s]',
|
||||||
|
bitcoreRpc.host,
|
||||||
|
bitcoreRpc.port,
|
||||||
|
bitcoreRpc.user,
|
||||||
|
bitcoreRpc.pass?'yes':'no'
|
||||||
|
);
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
|
||||||
|
Rpc.getRpcInfo = function(txid, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
bitcoreRpc.getRawTransaction(txid, 1, function(err, txInfo) {
|
||||||
|
|
||||||
|
// Not found?
|
||||||
|
if (err && err.code === -5) return cb();
|
||||||
|
if (err) return cb(self.errMsg(err));
|
||||||
|
|
||||||
|
var info = self._parseRpcResult(txInfo.result);
|
||||||
|
|
||||||
|
return cb(null,info);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Rpc.blockIndex = function(height, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
bitcoreRpc.getBlockHash(height, function(err, bh){
|
||||||
|
if (err) return cb(self.errMsg(err));
|
||||||
|
cb(null, { blockHash: bh.result });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Rpc.getBlock = function(hash, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
bitcoreRpc.getBlock(hash, function(err,info) {
|
||||||
|
// Not found?
|
||||||
|
if (err && err.code === -5) return cb();
|
||||||
|
if (err) return cb(self.errMsg(err));
|
||||||
|
|
||||||
|
|
||||||
|
if (info.result.height)
|
||||||
|
info.result.reward = BitcoreBlock.getBlockValue(info.result.height) / util.COIN ;
|
||||||
|
|
||||||
|
return cb(err,info);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return Rpc;
|
||||||
|
}
|
||||||
|
module.defineClass(spec);
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ function spec() {
|
||||||
function(err) {
|
function(err) {
|
||||||
if (!err) self._handleBroadcast(b.hash, null, updatedAddrs);
|
if (!err) self._handleBroadcast(b.hash, null, updatedAddrs);
|
||||||
if (err && err.toString().match(/WARN/) ) {
|
if (err && err.toString().match(/WARN/) ) {
|
||||||
console.log(err);
|
//console.log(err);
|
||||||
err=null;
|
err=null;
|
||||||
}
|
}
|
||||||
return cb(err);
|
return cb(err);
|
||||||
|
|
|
@ -25,7 +25,7 @@ function spec(b) {
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
var TransactionRpc = require('./TransactionRpc').class(),
|
var Rpc = b.rpc || require('./Rpc').class(),
|
||||||
util = require('bitcore/util/util'),
|
util = require('bitcore/util/util'),
|
||||||
levelup = require('levelup'),
|
levelup = require('levelup'),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
|
@ -224,7 +224,7 @@ function spec(b) {
|
||||||
TransactionDb.prototype._getInfo = function(txid, next) {
|
TransactionDb.prototype._getInfo = function(txid, next) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
TransactionRpc.getRpcInfo(txid, function(err, info) {
|
Rpc.getRpcInfo(txid, function(err, info) {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
|
|
||||||
self._fillOutpoints(info, function() {
|
self._fillOutpoints(info, function() {
|
||||||
|
@ -573,7 +573,7 @@ function spec(b) {
|
||||||
// TODO: parse it from networks.genesisTX?
|
// TODO: parse it from networks.genesisTX?
|
||||||
if (t === genesisTXID) return each_cb();
|
if (t === genesisTXID) return each_cb();
|
||||||
|
|
||||||
TransactionRpc.getRpcInfo(t, function(err, inInfo) {
|
Rpc.getRpcInfo(t, function(err, inInfo) {
|
||||||
if (!inInfo) return each_cb(err);
|
if (!inInfo) return each_cb(err);
|
||||||
|
|
||||||
return self.add(inInfo, blockHash, each_cb);
|
return self.add(inInfo, blockHash, each_cb);
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
require('classtool');
|
|
||||||
|
|
||||||
|
|
||||||
function spec(b) {
|
|
||||||
var RpcClient = require('bitcore/RpcClient').class(),
|
|
||||||
BitcoreTransaction = require('bitcore/Transaction').class(),
|
|
||||||
util = require('bitcore/util/util'),
|
|
||||||
config = require('../config/config');
|
|
||||||
|
|
||||||
var rpc = b.rpc || new RpcClient(config.bitcoind);
|
|
||||||
|
|
||||||
function TransactionRpc() {
|
|
||||||
}
|
|
||||||
|
|
||||||
TransactionRpc._parseRpcResult = function(info) {
|
|
||||||
var b = new Buffer(info.hex,'hex');
|
|
||||||
var tx = new BitcoreTransaction();
|
|
||||||
tx.parse(b);
|
|
||||||
|
|
||||||
// Inputs
|
|
||||||
if (tx.isCoinBase()) {
|
|
||||||
info.isCoinBase = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var n =0;
|
|
||||||
info.vin.forEach(function(i) {
|
|
||||||
i.n = n++;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Outputs
|
|
||||||
var valueOutSat = 0;
|
|
||||||
info.vout.forEach( function(o) {
|
|
||||||
valueOutSat += o.value * util.COIN;
|
|
||||||
});
|
|
||||||
info.valueOut = parseInt(valueOutSat) / util.COIN;
|
|
||||||
info.size = b.length;
|
|
||||||
|
|
||||||
return info;
|
|
||||||
};
|
|
||||||
|
|
||||||
TransactionRpc.getRpcInfo = function(txid, cb) {
|
|
||||||
var Self = this;
|
|
||||||
|
|
||||||
rpc.getRawTransaction(txid, 1, function(err, txInfo) {
|
|
||||||
|
|
||||||
// Not found?
|
|
||||||
if (err && err.code === -5) return cb();
|
|
||||||
if (err) return cb(err);
|
|
||||||
|
|
||||||
var info = Self._parseRpcResult(txInfo.result);
|
|
||||||
|
|
||||||
return cb(null,info);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return TransactionRpc;
|
|
||||||
}
|
|
||||||
module.defineClass(spec);
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue