conflict solved
This commit is contained in:
commit
3e9c0e0517
|
@ -72,7 +72,6 @@ console.log('[blocks.js.60]: could not get %s from RPC. Orphan? Error?', blockha
|
|||
* List of blocks by date
|
||||
*/
|
||||
exports.list = function(req, res) {
|
||||
var limit = req.query.limit || -1;
|
||||
var isToday = false;
|
||||
|
||||
//helper to convert timestamps to yyyy-mm-dd format
|
||||
|
@ -103,14 +102,18 @@ exports.list = function(req, res) {
|
|||
var prev = formatTimestamp(new Date((gte - 86400) * 1000));
|
||||
var next = formatTimestamp(new Date(lte * 1000));
|
||||
|
||||
bdb.getBlocksByDate(gte, lte, limit, function(err, blocks) {
|
||||
bdb.getBlocksByDate(gte, lte, function(err, blocks) {
|
||||
if (err) {
|
||||
res.status(500).send(err);
|
||||
}
|
||||
else {
|
||||
var blockshashList = [];
|
||||
for(var i=0;i<blocks.length;i++) {
|
||||
blockshashList.unshift(blocks[i].hash);
|
||||
var limit = parseInt(req.query.limit || blocks.length);
|
||||
if (blocks.length < limit) {
|
||||
limit = blocks.length;
|
||||
}
|
||||
for(var i=0;i<limit;i++) {
|
||||
blockshashList.push(blocks[i].hash);
|
||||
}
|
||||
async.mapSeries(blockshashList, getBlock, function(err, allblocks) {
|
||||
res.jsonp({
|
||||
|
@ -118,9 +121,10 @@ exports.list = function(req, res) {
|
|||
length: allblocks.length,
|
||||
pagination: {
|
||||
next: next,
|
||||
prev: prev,
|
||||
current: dateStr,
|
||||
isToday: isToday
|
||||
prev: prev,
|
||||
currentTs: lte-1,
|
||||
current: dateStr,
|
||||
isToday: isToday
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,15 +14,15 @@ module.exports.init = function(app, io_ext) {
|
|||
});
|
||||
};
|
||||
|
||||
module.exports.broadcast_tx = function(tx) {
|
||||
module.exports.broadcastTx = function(tx) {
|
||||
if (ios) ios.sockets.in('inv').emit('tx', tx);
|
||||
};
|
||||
|
||||
module.exports.broadcast_block = function(block) {
|
||||
module.exports.broadcastBlock = function(block) {
|
||||
if (ios) ios.sockets.in('inv').emit('block', block);
|
||||
};
|
||||
|
||||
module.exports.broadcast_address_tx = function(address, tx) {
|
||||
module.exports.broadcastAddressTx = function(address, tx) {
|
||||
if (ios) ios.sockets.in(address).emit(address, tx);
|
||||
};
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@ function spec() {
|
|||
var a = new BitcoreAddress(addrStr);
|
||||
a.validate();
|
||||
this.addrStr = addrStr;
|
||||
|
||||
|
||||
|
||||
Object.defineProperty(this, 'totalSent', {
|
||||
get: function() {
|
||||
return parseFloat(this.totalSentSat) / parseFloat(BitcoreUtil.COIN);
|
||||
|
@ -56,26 +55,30 @@ function spec() {
|
|||
|
||||
Address.prototype.update = function(next) {
|
||||
var self = this;
|
||||
if (!self.addrStr) return next();
|
||||
|
||||
var db = new TransactionDb();
|
||||
async.series([
|
||||
function (cb) {
|
||||
db.fromAddr(self.addrStr, function(err,txOut){
|
||||
if (err) return cb(err);
|
||||
txOut.forEach(function(txItem){
|
||||
var v = txItem.value_sat;
|
||||
|
||||
self.totalReceivedSat += v;
|
||||
self.transactions.push(txItem.txid);
|
||||
if (! txItem.spendTxId) {
|
||||
// unspent
|
||||
self.balanceSat += v;
|
||||
self.txApperances +=1;
|
||||
}
|
||||
else {
|
||||
// spent
|
||||
self.totalSentSat += v;
|
||||
self.transactions.push(txItem.spendTxId);
|
||||
self.txApperances +=2;
|
||||
if (txItem.isConfirmed) {
|
||||
var v = txItem.value_sat;
|
||||
self.totalReceivedSat += v;
|
||||
self.transactions.push(txItem.txid);
|
||||
if (! txItem.spendTxId || !txItem.spendIsConfirmed) {
|
||||
// unspent
|
||||
self.balanceSat += v;
|
||||
self.txApperances +=1;
|
||||
}
|
||||
else {
|
||||
// spent
|
||||
self.totalSentSat += v;
|
||||
self.transactions.push(txItem.spendTxId);
|
||||
self.txApperances +=2;
|
||||
}
|
||||
}
|
||||
});
|
||||
return cb();
|
||||
|
|
|
@ -5,10 +5,12 @@ require('classtool');
|
|||
function spec() {
|
||||
var async = require('async');
|
||||
var RpcClient = require('bitcore/RpcClient').class();
|
||||
var BlockDb = require('../../lib/BlockDb').class();
|
||||
var config = require('../../config/config');
|
||||
var rpc = new RpcClient(config.bitcoind);
|
||||
|
||||
function Status() {
|
||||
this.bDb = new BlockDb();
|
||||
}
|
||||
|
||||
Status.prototype.getInfo = function(next) {
|
||||
|
@ -21,7 +23,7 @@ function spec() {
|
|||
that.info = info.result;
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
},
|
||||
], function (err) {
|
||||
return next(err);
|
||||
});
|
||||
|
@ -69,7 +71,8 @@ function spec() {
|
|||
that.bestblockhash = bbh.result;
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
], function (err) {
|
||||
return next(err);
|
||||
});
|
||||
|
@ -77,27 +80,29 @@ function spec() {
|
|||
|
||||
Status.prototype.getLastBlockHash = function(next) {
|
||||
var that = this;
|
||||
|
||||
async.waterfall(
|
||||
[
|
||||
function(callback){
|
||||
rpc.getBlockCount(function(err, bc){
|
||||
if (err) return callback(err);
|
||||
callback(null, bc.result);
|
||||
});
|
||||
},
|
||||
function(bc, callback){
|
||||
rpc.getBlockHash(bc, function(err, bh){
|
||||
if (err) return callback(err);
|
||||
callback(null, bh.result);
|
||||
});
|
||||
}
|
||||
],
|
||||
function (err, result) {
|
||||
that.lastblockhash = result;
|
||||
return next();
|
||||
}
|
||||
);
|
||||
that.bDb.getTip(function(err,tip) {
|
||||
that.syncTipHash = tip;
|
||||
async.waterfall(
|
||||
[
|
||||
function(callback){
|
||||
rpc.getBlockCount(function(err, bc){
|
||||
if (err) return callback(err);
|
||||
callback(null, bc.result);
|
||||
});
|
||||
},
|
||||
function(bc, callback){
|
||||
rpc.getBlockHash(bc, function(err, bh){
|
||||
if (err) return callback(err);
|
||||
callback(null, bh.result);
|
||||
});
|
||||
}
|
||||
],
|
||||
function (err, result) {
|
||||
that.lastblockhash = result;
|
||||
return next();
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return Status;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var config = require('../config/config'),
|
||||
levelup = require('levelup');
|
||||
|
||||
|
||||
|
||||
var s = process.argv[2];
|
||||
var isBlock = process.argv[3] === '1';
|
||||
|
||||
|
||||
var dbPath = config.leveldb + (isBlock ? '/blocks' : '/txs');
|
||||
console.log('DB: ',dbPath); //TODO
|
||||
|
||||
|
||||
|
||||
var db = levelup(dbPath );
|
||||
|
||||
|
||||
db.createReadStream({start: s, end: s+'~'})
|
||||
.on('data', function (data) {
|
||||
console.log(data.key + ' => ' + data.value); //TODO
|
||||
})
|
||||
.on('error', function () {
|
||||
})
|
||||
.on('end', function () {
|
||||
});
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var
|
||||
config = require('../config/config'),
|
||||
levelup = require('levelup');
|
||||
|
||||
|
||||
db = levelup(config.leveldb + '/txs');
|
||||
|
||||
var s = 'txouts-addr-mgqvRGJMwR9JU5VhJ3x9uX9MTkzTsmmDgQ';
|
||||
db.createReadStream({start: s, end: s+'~'})
|
||||
.on('data', function (data) {
|
||||
console.log('[block-level.js.11:data:]',data); //TODO
|
||||
if (data==false) c++;
|
||||
})
|
||||
.on('end', function () {
|
||||
});
|
||||
|
||||
|
|
@ -7,8 +7,8 @@ txindex=1
|
|||
#rpcallowip=192.168.1.*
|
||||
#rpcallowip='192.168.1.*'
|
||||
#rpcallowip=127.0.0.1
|
||||
#rpcallowip=*
|
||||
|
||||
rpcallowip=*
|
||||
|
||||
port=18333
|
||||
rpcport=18332
|
||||
testnet=3
|
||||
|
|
35
insight.js
35
insight.js
|
@ -40,6 +40,21 @@ var walk = function(path) {
|
|||
|
||||
walk(models_path);
|
||||
|
||||
var syncOpts = {
|
||||
};
|
||||
|
||||
/**
|
||||
* p2pSync process
|
||||
*/
|
||||
if (!config.disableP2pSync) {
|
||||
var ps = new PeerSync();
|
||||
ps.init({
|
||||
shouldBroadcast: true,
|
||||
}, function() {
|
||||
ps.run();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* historic_sync process
|
||||
*/
|
||||
|
@ -49,8 +64,7 @@ if (!config.disableHistoricSync) {
|
|||
historicSync = new HistoricSync();
|
||||
|
||||
historicSync.init({
|
||||
shouldBroadcast: true,
|
||||
networkName: config.network
|
||||
shouldBroadcastSync: true,
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
var txt = 'ABORTED with error: ' + err.message;
|
||||
|
@ -60,25 +74,16 @@ if (!config.disableHistoricSync) {
|
|||
historicSync.smartImport({}, function(err){
|
||||
var txt = 'ended.';
|
||||
if (err) txt = 'ABORTED with error: ' + err.message;
|
||||
else
|
||||
ps.allowReorgs = true;
|
||||
|
||||
console.log('[historic_sync] ' + txt, historicSync.info());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* p2pSync process
|
||||
*/
|
||||
if (!config.disableP2pSync) {
|
||||
var ps = new PeerSync();
|
||||
ps.init({
|
||||
broadcast_txs: true,
|
||||
broadcast_address_tx: true,
|
||||
broadcast_blocks: true,
|
||||
}, function() {
|
||||
ps.run();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//express settings
|
||||
require('./config/express')(expressApp, historicSync);
|
||||
|
|
|
@ -5,8 +5,11 @@ require('classtool');
|
|||
|
||||
function spec(b) {
|
||||
|
||||
var TIMESTAMP_ROOT = 'b-ts-'; // b-ts-<ts> => <hash>
|
||||
var PREV_ROOT = 'b-prev-'; // b-prev-<hash> => <prev_hash> (0 if orphan)
|
||||
var TIMESTAMP_PREFIX = 'b-ts-'; // b-ts-<ts> => <hash>
|
||||
var PREV_PREFIX = 'b-prev-'; // b-prev-<hash> => <prev_hash>
|
||||
var NEXT_PREFIX = 'b-next-'; // b-next-<hash> => <next_hash>
|
||||
var MAIN_PREFIX = 'b-main-'; // b-main-<hash> => 1/0
|
||||
var TIP = 'b-tip-'; // last block on the chain
|
||||
|
||||
|
||||
/**
|
||||
|
@ -20,7 +23,6 @@ function spec(b) {
|
|||
var db = b.db || levelup(config.leveldb + '/blocks');
|
||||
var rpc = b.rpc || new RpcClient(config.bitcoind);
|
||||
|
||||
|
||||
var BlockDb = function() {
|
||||
};
|
||||
|
||||
|
@ -38,53 +40,76 @@ function spec(b) {
|
|||
});
|
||||
};
|
||||
|
||||
// adds a block. Does not update Next pointer in
|
||||
// the block prev to the new block, nor TIP pointer
|
||||
//
|
||||
BlockDb.prototype.add = function(b, cb) {
|
||||
if (!b.hash) return cb(new Error('no Hash at Block.save'));
|
||||
|
||||
|
||||
var time_key = TIMESTAMP_ROOT +
|
||||
var time_key = TIMESTAMP_PREFIX +
|
||||
( b.time || Math.round(new Date().getTime() / 1000) );
|
||||
|
||||
db.batch()
|
||||
return db.batch()
|
||||
.put(time_key, b.hash)
|
||||
.put(PREV_ROOT + b.hash, b.previousblockhash)
|
||||
.put(MAIN_PREFIX + b.hash, 1)
|
||||
.put(PREV_PREFIX + b.hash, b.previousblockhash)
|
||||
.write(cb);
|
||||
};
|
||||
|
||||
|
||||
|
||||
BlockDb.prototype.setOrphan = function(hash, cb) {
|
||||
var k = PREV_ROOT + hash;
|
||||
|
||||
db.get(k, function (err,oldPrevHash) {
|
||||
if (err || !oldPrevHash) return cb(err);
|
||||
db.put(PREV_ROOT + hash, 0, function() {
|
||||
return cb(err, oldPrevHash);
|
||||
});
|
||||
BlockDb.prototype.getTip = function(cb) {
|
||||
db.get(TIP, function(err, val) {
|
||||
return cb(err,val);
|
||||
});
|
||||
// We keep the block in TIMESTAMP_ROOT
|
||||
};
|
||||
|
||||
//mainly for testing
|
||||
BlockDb.prototype.setPrev = function(hash, prevHash, cb) {
|
||||
db.put(PREV_ROOT + hash, prevHash, function(err) {
|
||||
BlockDb.prototype.setTip = function(hash, cb) {
|
||||
db.put(TIP, hash, function(err) {
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
//mainly for testing
|
||||
BlockDb.prototype.setPrev = function(hash, prevHash, cb) {
|
||||
db.put(PREV_PREFIX + hash, prevHash, function(err) {
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
BlockDb.prototype.getPrev = function(hash, cb) {
|
||||
db.get(PREV_ROOT + hash, function(err,val) {
|
||||
db.get(PREV_PREFIX + hash, function(err,val) {
|
||||
if (err && err.notFound) { err = null; val = null;}
|
||||
return cb(err,val);
|
||||
});
|
||||
};
|
||||
|
||||
BlockDb.prototype.getNext = function(hash, cb) {
|
||||
db.get(NEXT_PREFIX + hash, function(err,val) {
|
||||
if (err && err.notFound) { err = null; val = null;}
|
||||
return cb(err,val);
|
||||
});
|
||||
};
|
||||
|
||||
BlockDb.prototype.isMain = function(hash, cb) {
|
||||
db.get(MAIN_PREFIX + hash, function(err, val) {
|
||||
if (err && err.notFound) { err = null; val = 0;}
|
||||
return cb(err,parseInt(val));
|
||||
});
|
||||
};
|
||||
|
||||
BlockDb.prototype.setMain = function(hash, isMain, cb) {
|
||||
if (!isMain) console.log('\tNew orphan: %s',hash);
|
||||
db.put(MAIN_PREFIX + hash, isMain?1:0, function(err) {
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
BlockDb.prototype.setNext = function(hash, nextHash, cb) {
|
||||
db.put(NEXT_PREFIX + hash, nextHash, function(err) {
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
BlockDb.prototype.countNotOrphan = function(cb) {
|
||||
var c = 0;
|
||||
console.log('Counting connected blocks. This could take some minutes');
|
||||
db.createReadStream({start: PREV_ROOT, end: PREV_ROOT + '~' })
|
||||
db.createReadStream({start: MAIN_PREFIX, end: MAIN_PREFIX + '~' })
|
||||
.on('data', function (data) {
|
||||
if (data.value !== 0) c++;
|
||||
})
|
||||
|
@ -96,8 +121,9 @@ function spec(b) {
|
|||
});
|
||||
};
|
||||
|
||||
// .has() return true orphans also
|
||||
BlockDb.prototype.has = function(hash, cb) {
|
||||
var k = PREV_ROOT + hash;
|
||||
var k = PREV_PREFIX + hash;
|
||||
db.get(k, function (err,val) {
|
||||
var ret;
|
||||
if (err && err.notFound) {
|
||||
|
@ -118,8 +144,8 @@ function spec(b) {
|
|||
if (err && err.code === -5) return cb();
|
||||
if (err) return cb(err);
|
||||
|
||||
info.reward = BitcoreBlock.getBlockValue(info.height) / util.COIN ;
|
||||
|
||||
if (info.result.height)
|
||||
info.result.reward = BitcoreBlock.getBlockValue(info.result.height) / util.COIN ;
|
||||
return cb(null, {
|
||||
hash: hash,
|
||||
info: info.result,
|
||||
|
@ -127,17 +153,16 @@ function spec(b) {
|
|||
});
|
||||
};
|
||||
|
||||
BlockDb.prototype.getBlocksByDate = function(start_ts, end_ts, limit, cb) {
|
||||
BlockDb.prototype.getBlocksByDate = function(start_ts, end_ts, cb) {
|
||||
var list = [];
|
||||
db.createReadStream({
|
||||
start: TIMESTAMP_ROOT + start_ts,
|
||||
end: TIMESTAMP_ROOT + end_ts,
|
||||
fillCache: true,
|
||||
limit: parseInt(limit) // force to int
|
||||
start: TIMESTAMP_PREFIX + start_ts,
|
||||
end: TIMESTAMP_PREFIX + end_ts,
|
||||
fillCache: true
|
||||
})
|
||||
.on('data', function (data) {
|
||||
list.push({
|
||||
ts: data.key.replace(TIMESTAMP_ROOT, ''),
|
||||
ts: data.key.replace(TIMESTAMP_PREFIX, ''),
|
||||
hash: data.value,
|
||||
});
|
||||
})
|
||||
|
@ -145,7 +170,7 @@ function spec(b) {
|
|||
return cb(err);
|
||||
})
|
||||
.on('end', function () {
|
||||
return cb(null, list);
|
||||
return cb(null, list.reverse());
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ function spec() {
|
|||
skippedBlocks: this.skippedBlocks,
|
||||
syncedBlocks: this.syncedBlocks,
|
||||
orphanBlocks: this.orphanBlocks,
|
||||
syncTipHash: this.sync.tip,
|
||||
error: this.error,
|
||||
type: this.type,
|
||||
};
|
||||
|
@ -105,6 +106,8 @@ function spec() {
|
|||
HistoricSync.prototype.showProgress = function() {
|
||||
var self = this;
|
||||
|
||||
if ( ( self.syncedBlocks + self.skippedBlocks) % self.step !== 1) return;
|
||||
|
||||
if (self.error) {
|
||||
p('ERROR: ' + self.error);
|
||||
}
|
||||
|
@ -114,9 +117,14 @@ function spec() {
|
|||
|
||||
p(util.format('status: [%d%%] skipped: %d ', self.syncPercentage, self.skippedBlocks));
|
||||
}
|
||||
if (self.opts.shouldBroadcast) {
|
||||
if (self.opts.shouldBroadcastSync) {
|
||||
sockets.broadcastSyncInfo(self.info());
|
||||
}
|
||||
|
||||
//TODO
|
||||
// if (self.syncPercentage > 10) {
|
||||
// process.exit(-1);
|
||||
// }
|
||||
};
|
||||
|
||||
HistoricSync.prototype.getPrevNextBlock = function(blockHash, blockEnd, scanOpts, cb) {
|
||||
|
@ -143,18 +151,23 @@ function spec() {
|
|||
},
|
||||
//show some (inacurate) status
|
||||
function(c) {
|
||||
if ( ( self.syncedBlocks + self.skippedBlocks) % self.step === 1) {
|
||||
self.showProgress();
|
||||
}
|
||||
|
||||
self.showProgress();
|
||||
return c();
|
||||
},
|
||||
|
||||
function(c) {
|
||||
self.rpc.getBlock(blockHash, function(err, ret) {
|
||||
if (err) return c(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');
|
||||
}
|
||||
else {
|
||||
blockInfo = null;
|
||||
}
|
||||
|
||||
blockInfo = ret ? ret.result : null;
|
||||
return c();
|
||||
});
|
||||
},
|
||||
|
@ -162,34 +175,26 @@ function spec() {
|
|||
function(c) {
|
||||
if (existed) return c();
|
||||
|
||||
self.sync.storeBlock(blockInfo, function(err) {
|
||||
// When storing files from RPC recusively, reorgs are disabled
|
||||
self.sync.storeTipBlock(blockInfo, false, function(err) {
|
||||
return c(err);
|
||||
});
|
||||
},
|
||||
/* TODO: Should Start to sync backwards? (this is for partial syncs)
|
||||
function(c) {
|
||||
|
||||
if (blockInfo.result.prevblockhash != current.blockHash) {
|
||||
p("reorg?");
|
||||
scanOpts.prev = 1;
|
||||
}
|
||||
return c();
|
||||
}
|
||||
*/
|
||||
], function(err) {
|
||||
}], function(err) {
|
||||
|
||||
if (err) {
|
||||
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]', blockHash, err, self.syncedBlocks));
|
||||
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]',
|
||||
blockHash, err, self.syncedBlocks));
|
||||
return cb(err);
|
||||
}
|
||||
else {
|
||||
self.status = 'syncing';
|
||||
}
|
||||
|
||||
if ( (scanOpts.upToExisting && existed && self.syncedBlocks >= self.blockChainHeight) ||
|
||||
if ( (scanOpts.upToExisting && existed &&
|
||||
self.syncedBlocks >= self.blockChainHeight) ||
|
||||
(blockEnd && blockEnd === blockHash)) {
|
||||
self.status = 'finished';
|
||||
p('DONE. Found existing block: ', blockHash);
|
||||
p('DONE. Found block: ', blockHash);
|
||||
self.showProgress();
|
||||
return cb(err);
|
||||
}
|
||||
|
@ -251,106 +256,79 @@ function spec() {
|
|||
return addrStrs;
|
||||
};
|
||||
|
||||
HistoricSync.prototype.getBlockFromFile = function(scanOpts, cb) {
|
||||
HistoricSync.prototype.getBlockFromFile = function(cb) {
|
||||
var self = this;
|
||||
|
||||
var blockInfo;
|
||||
var existed;
|
||||
async.series([
|
||||
//show some (inacurate) status
|
||||
function(c) {
|
||||
if ( ( self.syncedBlocks + self.skippedBlocks) % self.step === 1) {
|
||||
self.showProgress();
|
||||
}
|
||||
|
||||
return c();
|
||||
},
|
||||
//get Info
|
||||
function(c) {
|
||||
self.blockExtractor.getNextBlock(function(err, b) {
|
||||
if (err || ! b) return cb(err);
|
||||
|
||||
self.blockExtractor.getNextBlock(function(err, b) {
|
||||
if (err || ! b) return c(err);
|
||||
blockInfo = b.getStandardizedObject(b.txs, self.network);
|
||||
// blockInfo.curWork = Deserialize.intFromCompact(b.bits);
|
||||
// We keep the RPC field names
|
||||
blockInfo.previousblockhash = blockInfo.prev_block;
|
||||
|
||||
blockInfo = b.getStandardizedObject(b.txs, self.network);
|
||||
// blockInfo.curWork = Deserialize.intFromCompact(b.bits);
|
||||
// We keep the RPC field names
|
||||
blockInfo.previousblockhash = blockInfo.prev_block;
|
||||
|
||||
var ti=0;
|
||||
// Get TX Address
|
||||
b.txs.forEach(function(t) {
|
||||
var ti=0;
|
||||
// Get TX Address
|
||||
b.txs.forEach(function(t) {
|
||||
|
||||
|
||||
var objTx = blockInfo.tx[ti++];
|
||||
var objTx = blockInfo.tx[ti++];
|
||||
|
||||
//add time from block
|
||||
objTx.time = blockInfo.time;
|
||||
//add time from block
|
||||
objTx.time = blockInfo.time;
|
||||
|
||||
var to=0;
|
||||
t.outs.forEach( function(o) {
|
||||
var to=0;
|
||||
t.outs.forEach( function(o) {
|
||||
|
||||
|
||||
var s = new Script(o.s);
|
||||
var addrs = self.getAddrStr(s);
|
||||
var s = new Script(o.s);
|
||||
var addrs = self.getAddrStr(s);
|
||||
|
||||
// support only p2pubkey p2pubkeyhash and p2sh
|
||||
if (addrs.length === 1) {
|
||||
objTx.out[to].addrStr = addrs[0];
|
||||
}
|
||||
to++;
|
||||
});
|
||||
// support only for p2pubkey p2pubkeyhash and p2sh
|
||||
if (addrs.length === 1) {
|
||||
objTx.out[to].addrStr = addrs[0];
|
||||
}
|
||||
to++;
|
||||
});
|
||||
|
||||
return c();
|
||||
});
|
||||
},
|
||||
//check prev
|
||||
function(c) {
|
||||
if (blockInfo && self.prevHash && blockInfo.previousblockhash !== self.prevHash) {
|
||||
|
||||
console.log('Hole found @%s', blockInfo.hash);
|
||||
console.log('From: %s To: %s', self.prevHash, blockInfo.previousblockhash);
|
||||
self.sync.checkOrphan(self.prevHash, blockInfo.previousblockhash, c);
|
||||
}
|
||||
else return c();
|
||||
},
|
||||
//check it
|
||||
function(c) {
|
||||
if (!blockInfo) return c();
|
||||
|
||||
self.sync.bDb.has(blockInfo.hash, function(err, had) {
|
||||
existed = had;
|
||||
return c(err);
|
||||
});
|
||||
},
|
||||
//store it
|
||||
function(c) {
|
||||
if (!blockInfo || existed) return c();
|
||||
|
||||
self.sync.storeBlock(blockInfo, function(err) {
|
||||
return c(err);
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
if (blockInfo && blockInfo.hash) {
|
||||
self.prevHash = blockInfo.hash;
|
||||
if (existed)
|
||||
self.skippedBlocks++;
|
||||
else
|
||||
self.syncedBlocks++;
|
||||
} else
|
||||
self.status = 'finished';
|
||||
|
||||
return c();
|
||||
},
|
||||
], function(err) {
|
||||
if (err) {
|
||||
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]', blockInfo ? blockInfo.hash : '-', err, self.syncedBlocks));
|
||||
}
|
||||
return cb(err);
|
||||
return cb(err,blockInfo);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
HistoricSync.prototype.nextBlockFromFile = function(scanOpts, cb) {
|
||||
var self = this;
|
||||
|
||||
self.showProgress();
|
||||
|
||||
self.getBlockFromFile(function(err, blockInfo) {
|
||||
if (err) {
|
||||
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]',
|
||||
blockInfo ? blockInfo.hash : '-', err, self.syncedBlocks));
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
self.sync.storeTipBlock(blockInfo, function(err) {
|
||||
if (blockInfo && blockInfo.hash) {
|
||||
self.syncedBlocks++;
|
||||
} else
|
||||
self.status = 'finished';
|
||||
|
||||
if (err) {
|
||||
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]',
|
||||
blockInfo ? blockInfo.hash : '-', err, self.syncedBlocks));
|
||||
}
|
||||
return cb(err);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
HistoricSync.prototype.countNotOrphan = function(cb) {
|
||||
var self = this;
|
||||
|
||||
|
@ -452,12 +430,15 @@ function spec() {
|
|||
p(' scanOpts: ', JSON.stringify(scanOpts));
|
||||
|
||||
if (scanOpts.fromFiles) {
|
||||
|
||||
self.status = 'syncing';
|
||||
self.type = 'from .dat Files';
|
||||
self.type = 'from .dat Files';
|
||||
|
||||
|
||||
async.whilst(function() {
|
||||
return self.status === 'syncing';
|
||||
}, function (w_cb) {
|
||||
self.getBlockFromFile(scanOpts, function(err) {
|
||||
self.nextBlockFromFile(scanOpts, function(err) {
|
||||
setImmediate(function(){
|
||||
return w_cb(err);
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@ function spec() {
|
|||
var Sync = require('./Sync').class();
|
||||
var Peer = require('bitcore/Peer').class();
|
||||
var config = require('../config/config');
|
||||
var networks = require('bitcore/networks');
|
||||
|
||||
var peerdb_fn = 'peerdb.json';
|
||||
|
||||
|
@ -16,18 +17,12 @@ function spec() {
|
|||
|
||||
PeerSync.prototype.init = function(opts, cb) {
|
||||
if (!opts) opts = {};
|
||||
var network = opts && (opts.network || 'testnet');
|
||||
|
||||
this.verbose = opts.verbose;
|
||||
this.peerdb = undefined;
|
||||
this.sync = new Sync({
|
||||
networkName: network
|
||||
});
|
||||
this.allowReorgs = false;
|
||||
|
||||
this.sync = new Sync();
|
||||
this.PeerManager = require('bitcore/PeerManager').createClass({
|
||||
opts: {
|
||||
network: network
|
||||
}
|
||||
network: (config.network === 'testnet' ? networks.testnet : networks.livenet)
|
||||
});
|
||||
this.peerman = new this.PeerManager();
|
||||
this.load_peers();
|
||||
|
@ -45,49 +40,42 @@ function spec() {
|
|||
fs.writeFileSync(peerdb_fn, JSON.stringify(this.peerdb));
|
||||
};
|
||||
|
||||
PeerSync.prototype.handle_inv = function(info) {
|
||||
var self = this;
|
||||
PeerSync.prototype.handleInv = function(info) {
|
||||
var invs = info.message.invs;
|
||||
invs.forEach(function(inv) {
|
||||
if (self.verbose) {
|
||||
console.log('[p2p_sync] Handle inv for a ' + CoinConst.MSG.to_str(inv.type));
|
||||
}
|
||||
console.log('[p2p_sync] Handle inv for a ' + CoinConst.MSG.to_str(inv.type));
|
||||
});
|
||||
// TODO: should limit the invs to objects we haven't seen yet
|
||||
info.conn.sendGetData(invs);
|
||||
};
|
||||
|
||||
PeerSync.prototype.handle_tx = function(info) {
|
||||
PeerSync.prototype.handleTx = function(info) {
|
||||
var tx = info.message.tx.getStandardizedObject();
|
||||
if (this.verbose) {
|
||||
console.log('[p2p_sync] Handle tx: ' + tx.hash);
|
||||
}
|
||||
console.log('[p2p_sync] Handle tx: ' + tx.hash);
|
||||
|
||||
this.sync.storeTxs([tx.hash], function(err) {
|
||||
if (err) {
|
||||
console.log('[PeerSync.js.71:err:]',err); //TODO
|
||||
console.log('[p2p_sync] Error in handle TX: ' + JSON.stringify(err));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
PeerSync.prototype.handle_block = function(info) {
|
||||
PeerSync.prototype.handleBlock = function(info) {
|
||||
var self = this;
|
||||
var block = info.message.block;
|
||||
var blockHash = coinUtil.formatHashFull(block.calcHash());
|
||||
if (this.verbose) {
|
||||
console.log('[p2p_sync] Handle block: ' + blockHash);
|
||||
}
|
||||
|
||||
console.log('[p2p_sync] Handle block: %s (allowReorgs: %s)', blockHash, self.allowReorgs);
|
||||
|
||||
var tx_hashes = block.txs.map(function(tx) {
|
||||
return coinUtil.formatHashFull(tx.hash);
|
||||
});
|
||||
|
||||
this.sync.storeBlock({
|
||||
this.sync.storeTipBlock({
|
||||
'hash': blockHash,
|
||||
'tx': tx_hashes,
|
||||
// TODO NEXT BLOCK / PREV BLOCK?
|
||||
},
|
||||
function(err) {
|
||||
'previousblockhash': coinUtil.formatHashFull(block.prev_hash),
|
||||
}, self.allowReorgs, function(err) {
|
||||
if (err) {
|
||||
console.log('[p2p_sync] Error in handle Block: ' + err);
|
||||
}
|
||||
|
@ -97,9 +85,7 @@ function spec() {
|
|||
PeerSync.prototype.handle_connected = function(data) {
|
||||
var peerman = data.pm;
|
||||
var peers_n = peerman.peers.length;
|
||||
if (this.verbose) {
|
||||
console.log('[p2p_sync] Connected to ' + peers_n + ' peer' + (peers_n !== 1 ? 's': ''));
|
||||
}
|
||||
console.log('[p2p_sync] Connected to ' + peers_n + ' peer' + (peers_n !== 1 ? 's': ''));
|
||||
};
|
||||
|
||||
PeerSync.prototype.run = function() {
|
||||
|
@ -111,9 +97,9 @@ function spec() {
|
|||
});
|
||||
|
||||
this.peerman.on('connection', function(conn) {
|
||||
conn.on('inv', self.handle_inv.bind(self));
|
||||
conn.on('block', self.handle_block.bind(self));
|
||||
conn.on('tx', self.handle_tx.bind(self));
|
||||
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.handle_connected.bind(self));
|
||||
|
||||
|
|
279
lib/Sync.js
279
lib/Sync.js
|
@ -11,15 +11,13 @@ function spec() {
|
|||
|
||||
|
||||
function Sync() {
|
||||
this.bDb = new BlockDb();
|
||||
this.txDb = new TransactionDb();
|
||||
}
|
||||
|
||||
Sync.prototype.init = function(opts, cb) {
|
||||
var self = this;
|
||||
|
||||
self.opts = opts;
|
||||
|
||||
this.bDb = new BlockDb(opts);
|
||||
this.txDb = new TransactionDb(opts);
|
||||
return cb();
|
||||
};
|
||||
|
||||
|
@ -39,101 +37,246 @@ function spec() {
|
|||
], 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) Declare D-E orphans (and possible invalidate TXs on them)
|
||||
*
|
||||
*
|
||||
* Case 3)
|
||||
*
|
||||
* A-B-C-D-E(TIP) ... NEW
|
||||
*
|
||||
* NEW is ignored
|
||||
*
|
||||
*/
|
||||
|
||||
Sync.prototype.storeBlock = function(block, cb) {
|
||||
Sync.prototype.storeTipBlock = function(b, allowReorgs, cb) {
|
||||
|
||||
if (typeof allowReorgs === 'function') {
|
||||
cb = allowReorgs;
|
||||
allowReorgs = true;
|
||||
}
|
||||
if (!b) return cb();
|
||||
|
||||
var self = this;
|
||||
var oldTip, oldNext, needReorg = false;
|
||||
var newPrev = b.previousblockhash;
|
||||
var updatedTxs, updatedAddrs;
|
||||
|
||||
async.series([
|
||||
function(c) {
|
||||
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) return c();
|
||||
|
||||
self.bDb.has(newPrev, function(err, val) {
|
||||
if (!val && newPrev.match(/^0+$/)) return c();
|
||||
return c(err ||
|
||||
(!val ? new Error('WARN: Ignoring block with non existing prev:' + b.hash) : null ));
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
self.txDb.createFromBlock(b, function(err, addrs) {
|
||||
updatedTxs = b.tx;
|
||||
updatedAddrs = addrs;
|
||||
return c(err);
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
if (!allowReorgs) return c();
|
||||
self.bDb.getTip(function(err, val) {
|
||||
oldTip = val;
|
||||
if (oldTip && newPrev !== oldTip) needReorg = true;
|
||||
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) {
|
||||
self.bDb.add(b, c);
|
||||
},
|
||||
function(c) {
|
||||
if (!needReorg) return c();
|
||||
console.log('NEW TIP: %s NEED REORG (old tip: %s)', b.hash, oldTip);
|
||||
// TODO should modify updatedTxs and addrs.
|
||||
self.processReorg(oldTip, oldNext, newPrev, c);
|
||||
},
|
||||
function(c) {
|
||||
self.bDb.setTip(b.hash, function(err) {
|
||||
if (err) return c(err);
|
||||
self.bDb.setNext(newPrev, b.hash, function(err) {
|
||||
return c(err);
|
||||
});
|
||||
});
|
||||
}],
|
||||
function(err) {
|
||||
if (!err) self._handleBroadcast(b.hash, updatedTxs, updatedAddrs);
|
||||
if (err && err.toString().match(/WARN/) ) {
|
||||
console.log(err);
|
||||
err=null;
|
||||
}
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
Sync.prototype.processReorg = function(oldTip, oldNext, newPrev, cb) {
|
||||
var self = this;
|
||||
|
||||
self.txDb.createFromBlock(block, function(err, insertedTxs, updateAddrs) {
|
||||
if (err) return cb(err);
|
||||
var orphanizeFrom;
|
||||
|
||||
self.bDb.add(block, function(err){
|
||||
if (err) return cb(err);
|
||||
self._handleBroadcast(block, insertedTxs, updateAddrs);
|
||||
return cb();
|
||||
});
|
||||
async.series([
|
||||
function(c) {
|
||||
self.bDb.isMain(newPrev, function(err,val) {
|
||||
if (!val) return c();
|
||||
|
||||
console.log('# Reorg Case 1)');
|
||||
// case 1
|
||||
orphanizeFrom = oldNext;
|
||||
return c(err);
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
if (orphanizeFrom) return c();
|
||||
|
||||
console.log('# Reorg Case 2)');
|
||||
self.setBranchConnectedBackwards(newPrev, function(err, yHash, newYHashNext) {
|
||||
if (err) return c(err);
|
||||
self.bDb.getNext(yHash, function(err, yHashNext) {
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
Sync.prototype.setBlockMain = function(hash, isMain, cb) {
|
||||
var self = this;
|
||||
self.bDb.setMain(hash, isMain, function(err) {
|
||||
if (err) return cb(err);
|
||||
return self.txDb.handleBlockChange(hash, isMain, cb);
|
||||
});
|
||||
};
|
||||
|
||||
Sync.prototype.checkOrphan = function(fromBlock, toBlock, c) {
|
||||
var self = this;
|
||||
|
||||
var hash = fromBlock;
|
||||
|
||||
var co = 0;
|
||||
var limit = 10;
|
||||
var cont = 1;
|
||||
Sync.prototype.setBranchOrphan = function(fromHash, cb) {
|
||||
var self = this,
|
||||
hashInterator = fromHash;
|
||||
|
||||
async.whilst(
|
||||
function () {
|
||||
if (++co > limit) {
|
||||
console.log('[Sync.js.109] WARN: Reach reog depth limit'); //TODO
|
||||
}
|
||||
return cont && hash && hash !== toBlock && co < limit;
|
||||
},
|
||||
function (w_c) {
|
||||
//check with RPC if the block is mainchain
|
||||
self.bDb.fromHashWithInfo(hash, function (err, info) {
|
||||
function() { return hashInterator; },
|
||||
function(c) {
|
||||
self.setBlockMain(hashInterator, false, function(err) {
|
||||
if (err) return cb(err);
|
||||
self.bDb.getNext(hashInterator, function (err, val) {
|
||||
hashInterator = val;
|
||||
return c(err);
|
||||
});
|
||||
});
|
||||
}, cb);
|
||||
};
|
||||
|
||||
if (!info) {
|
||||
console.log('[Sync.js.107:hash:ORPHAN]',hash); //TODO
|
||||
self.txDb.setOrphan(hash, function(err) {
|
||||
if (err) return w_c(err);
|
||||
self.bDb.setOrphan(hash, function(err, prevHash){
|
||||
hash = prevHash;
|
||||
return w_c(err);
|
||||
});
|
||||
Sync.prototype.setBranchConnectedBackwards = function(fromHash, cb) {
|
||||
var self = this,
|
||||
hashInterator = fromHash,
|
||||
lastHash = fromHash,
|
||||
isMain;
|
||||
|
||||
async.doWhilst(
|
||||
function(c) {
|
||||
self.setBlockMain(hashInterator, true, function (err) {
|
||||
if (err) return c(err);
|
||||
self.bDb.getPrev(hashInterator, function (err, val) {
|
||||
if (err) return c(err);
|
||||
lastHash = hashInterator;
|
||||
hashInterator = val;
|
||||
self.bDb.isMain(hashInterator, function (err, val) {
|
||||
isMain = val;
|
||||
return c();
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.log('[Sync.js.107:hash:NOT ORPHAN]',hash); //TODO
|
||||
cont = 0;
|
||||
return w_c();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
function (err) {
|
||||
return c(err);
|
||||
function() { return hashInterator && !isMain; },
|
||||
function(err) {
|
||||
console.log('\tFound yBlock:', hashInterator);
|
||||
return cb(err, hashInterator, lastHash);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Sync.prototype._handleBroadcast = function(hash, inserted_txs, updated_addrs) {
|
||||
Sync.prototype._handleBroadcast = function(hash, updatedTxs, updatedAddrs) {
|
||||
var self = this;
|
||||
|
||||
if (hash && self.opts.broadcast_blocks) {
|
||||
sockets.broadcast_block({hash: hash});
|
||||
}
|
||||
|
||||
if (inserted_txs && self.opts.broadcast_txs) {
|
||||
inserted_txs.forEach(function(tx) {
|
||||
sockets.broadcast_tx(tx);
|
||||
});
|
||||
}
|
||||
|
||||
if (updated_addrs && self.opts.broadcast_addresses) {
|
||||
updated_addrs.forEach(function(addr, txs){
|
||||
txs.forEach(function(addr, t){
|
||||
sockets.broadcast_address_tx(addr, {'txid': t});
|
||||
if (self.opts.shouldBroadcast) {
|
||||
if (hash) {
|
||||
sockets.broadcastBlock(hash);
|
||||
}
|
||||
|
||||
if (updatedTxs) {
|
||||
updatedTxs.forEach(function(tx) {
|
||||
sockets.broadcastTx(tx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (updatedAddrs ) {
|
||||
updatedAddrs.forEach(function(addr, txs){
|
||||
txs.forEach(function(addr, t){
|
||||
sockets.broadcastAddressTx(addr, t);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
Sync.prototype.storeTxs = function(txs, cb) {
|
||||
var self = this;
|
||||
|
||||
// TODO -- Peertopeer
|
||||
/*
|
||||
self.txDb.createFromTxs(txs, function(err, inserted_txs, updated_addrs) {
|
||||
self.txDb.createFromArray(txs, null, function(err, updatedAddrs) {
|
||||
if (err) return cb(err);
|
||||
|
||||
self._handleBroadcast(null, inserted_txs, updated_addrs);
|
||||
self._handleBroadcast(null, txs, updatedAddrs);
|
||||
return cb(err);
|
||||
});
|
||||
*/
|
||||
};
|
||||
return Sync;
|
||||
}
|
||||
|
|
|
@ -5,15 +5,18 @@ require('classtool');
|
|||
|
||||
function spec(b) {
|
||||
|
||||
// blockHash -> txid mapping (to reorgs)
|
||||
var ROOT = 'tx-b-'; //tx-b-<txid>-<block> => 1/0 (connected or not)
|
||||
// blockHash -> txid mapping
|
||||
var IN_BLK_PREFIX = 'tx-b-'; //tx-b-<txid>-<block> => 1/0 (connected or not)
|
||||
|
||||
// Only for orphan blocks
|
||||
var FROM_BLK_PREFIX = 'tx-'; //tx-<block>-<txid> => 1
|
||||
|
||||
// to show tx outs
|
||||
var OUTS_ROOT = 'txouts-'; //txouts-<txid>-<n> => [addr, btc_sat]
|
||||
var OUTS_PREFIX = 'txouts-'; //txouts-<txid>-<n> => [addr, btc_sat]
|
||||
|
||||
// to sum up addr balance
|
||||
var ADDR_ROOT = 'txouts-addr-'; //txouts-addr-<addr>-<ts>-<txid>-<n> => + btc_sat
|
||||
var SPEND_ROOT = 'txouts-spend-';//txouts-spend-<txid(out)>-<n(out)> => [txid(in),n(in),ts]
|
||||
var ADDR_PREFIX = 'txouts-addr-'; //txouts-addr-<addr>-<ts>-<txid>-<n> => + btc_sat
|
||||
var SPEND_PREFIX = 'txouts-spend-';//txouts-spend-<txid(out)>-<n(out)> => [txid(in),n(in),ts]
|
||||
|
||||
// TODO: use bitcore networks module
|
||||
var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b';
|
||||
|
@ -51,7 +54,7 @@ function spec(b) {
|
|||
// TransactionDb.prototype.fromTxIdOne = function(txid, cb) { TODO
|
||||
TransactionDb.prototype.has = function(txid, cb) {
|
||||
|
||||
var k = OUTS_ROOT + txid;
|
||||
var k = OUTS_PREFIX + txid;
|
||||
db.get(k, function (err,val) {
|
||||
|
||||
var ret;
|
||||
|
@ -69,7 +72,7 @@ function spec(b) {
|
|||
|
||||
TransactionDb.prototype.fromTxId = function(txid, cb) {
|
||||
|
||||
var k = OUTS_ROOT + txid;
|
||||
var k = OUTS_PREFIX + txid;
|
||||
var ret=[];
|
||||
|
||||
// outs.
|
||||
|
@ -87,7 +90,7 @@ function spec(b) {
|
|||
return cb(err);
|
||||
})
|
||||
.on('end', function () {
|
||||
var k = SPEND_ROOT + txid;
|
||||
var k = SPEND_PREFIX + txid;
|
||||
var l = ret.length;
|
||||
db.createReadStream({start: k, end: k + '~'})
|
||||
.on('data', function (data) {
|
||||
|
@ -174,23 +177,41 @@ function spec(b) {
|
|||
|
||||
TransactionDb.prototype.fromTxIdN = function(txid, n, cb) {
|
||||
|
||||
var k = OUTS_ROOT + txid + '-' + n;
|
||||
var k = OUTS_PREFIX + txid + '-' + n;
|
||||
|
||||
db.get(k, function (err,val) {
|
||||
if (err && err.notFound) {
|
||||
err = null;
|
||||
}
|
||||
var a = val.split(':');
|
||||
var a = val?val.split(':'):[null,null];
|
||||
return cb(err, a[0], parseInt(a[1]));
|
||||
});
|
||||
};
|
||||
|
||||
TransactionDb.prototype.fromAddr = function(addr, cb) {
|
||||
TransactionDb.prototype.fillConfirmations = function(o, cb) {
|
||||
var self = this;
|
||||
|
||||
var k = ADDR_ROOT + addr;
|
||||
self.isConfirmed(o.txid, function(err,is) {
|
||||
if (err) return cb(err);
|
||||
|
||||
o.isConfirmed = is;
|
||||
if (!o.spendTxId) return cb();
|
||||
|
||||
self.isConfirmed(o.spendTxId, function(err,is) {
|
||||
if (err) return cb(err);
|
||||
|
||||
o.spendIsConfirmed = is;
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TransactionDb.prototype.fromAddr = function(addr, cb) {
|
||||
var self = this;
|
||||
|
||||
var k = ADDR_PREFIX + addr;
|
||||
var ret=[];
|
||||
|
||||
//
|
||||
db.createReadStream({start: k, end: k + '~'})
|
||||
.on('data', function (data) {
|
||||
var k = data.key.split('-');
|
||||
|
@ -208,7 +229,7 @@ function spec(b) {
|
|||
.on('end', function () {
|
||||
|
||||
async.each(ret, function(o, e_c) {
|
||||
var k = SPEND_ROOT + o.txid + '-' + o.index;
|
||||
var k = SPEND_PREFIX + o.txid + '-' + o.index;
|
||||
db.get(k, function(err, val) {
|
||||
if (err && err.notFound) err=null;
|
||||
if (err || !val) return e_c(err);
|
||||
|
@ -220,8 +241,12 @@ function spec(b) {
|
|||
return e_c();
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
return cb(err,ret);
|
||||
function() {
|
||||
async.each(ret, function(o, e_c){
|
||||
self.fillConfirmations(o,e_c);
|
||||
},function(err) {
|
||||
return cb(err,ret);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -233,16 +258,16 @@ function spec(b) {
|
|||
async.series([
|
||||
function(c) {
|
||||
db.createReadStream({
|
||||
start: OUTS_ROOT + txid,
|
||||
end: OUTS_ROOT + txid + '~',
|
||||
start: OUTS_PREFIX + txid,
|
||||
end: OUTS_PREFIX + txid + '~',
|
||||
}).pipe(
|
||||
db.createWriteStream({type:'del'})
|
||||
).on('close', c);
|
||||
},
|
||||
function(c) {
|
||||
db.createReadStream({
|
||||
start: SPEND_ROOT + txid,
|
||||
end: SPEND_ROOT + txid + '~'
|
||||
start: SPEND_PREFIX + txid,
|
||||
end: SPEND_PREFIX + txid + '~'
|
||||
})
|
||||
.pipe(
|
||||
db.createWriteStream({type:'del'})
|
||||
|
@ -293,7 +318,8 @@ function spec(b) {
|
|||
};
|
||||
|
||||
|
||||
TransactionDb.prototype.add = function(tx, cb) {
|
||||
|
||||
TransactionDb.prototype.add = function(tx, blockhash, cb) {
|
||||
var self = this;
|
||||
var addrs = [];
|
||||
var is_new = true;
|
||||
|
@ -309,7 +335,7 @@ function spec(b) {
|
|||
async.forEachLimit(tx.vin, CONCURRENCY,
|
||||
function(i, next_out) {
|
||||
db.batch()
|
||||
.put( SPEND_ROOT + i.txid + '-' + i.vout ,
|
||||
.put( SPEND_PREFIX + i.txid + '-' + i.vout ,
|
||||
tx.txid + ':' + i.n + ':' + ts)
|
||||
.write(next_out);
|
||||
},
|
||||
|
@ -333,15 +359,15 @@ function spec(b) {
|
|||
! o.scriptPubKey.addresses[1] // TODO : not supported
|
||||
){
|
||||
// This is only to broadcast (WIP)
|
||||
// if (addrs.indexOf(o.scriptPubKey.addresses[0]) === -1) {
|
||||
// addrs.push(o.scriptPubKey.addresses[0]);
|
||||
// }
|
||||
if (addrs.indexOf(o.scriptPubKey.addresses[0]) === -1) {
|
||||
addrs.push(o.scriptPubKey.addresses[0]);
|
||||
}
|
||||
|
||||
var addr = o.scriptPubKey.addresses[0];
|
||||
var sat = Math.round(o.value * util.COIN);
|
||||
db.batch()
|
||||
.put( OUTS_ROOT + tx.txid + '-' + o.n, addr + ':' + sat)
|
||||
.put( ADDR_ROOT + addr + '-' + ts + '-' + tx.txid +
|
||||
.put( OUTS_PREFIX + tx.txid + '-' + o.n, addr + ':' + sat)
|
||||
.put( ADDR_PREFIX + addr + '-' + ts + '-' + tx.txid +
|
||||
'-' + o.n, sat)
|
||||
.write(next_out);
|
||||
|
||||
|
@ -363,19 +389,80 @@ function spec(b) {
|
|||
}
|
||||
return p_c();
|
||||
});
|
||||
}], function(err) {
|
||||
},
|
||||
function (p_c) {
|
||||
if (!blockhash) return p_c();
|
||||
return self.setConfirmation(tx.txid,blockhash, true, p_c);
|
||||
},
|
||||
], function(err) {
|
||||
return cb(err, addrs, is_new);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
TransactionDb.prototype.setConfirmation = function(txId, blockHash, confirmed, c) {
|
||||
if (!blockHash) return c();
|
||||
|
||||
confirmed = confirmed ? 1 : 0;
|
||||
|
||||
db.batch()
|
||||
.put(IN_BLK_PREFIX + txId + '-' + blockHash, confirmed)
|
||||
.put(FROM_BLK_PREFIX + blockHash + '-' + txId, 1)
|
||||
.write(c);
|
||||
};
|
||||
|
||||
|
||||
// This slowdown addr balance calculation by 100%
|
||||
TransactionDb.prototype.isConfirmed = function(txId, c) {
|
||||
var k = IN_BLK_PREFIX + txId;
|
||||
var ret = false;
|
||||
|
||||
db.createReadStream({start: k, end: k + '~'})
|
||||
.on('data', function (data) {
|
||||
if (data.value === '1') ret = true;
|
||||
})
|
||||
.on('error', function (err) {
|
||||
return c(err);
|
||||
})
|
||||
.on('end', function (err) {
|
||||
return c(err,ret);
|
||||
});
|
||||
};
|
||||
|
||||
TransactionDb.prototype.handleBlockChange = function(hash, isMain, cb) {
|
||||
var toChange = [];
|
||||
console.log('\tSearching Txs from block:' + hash);
|
||||
|
||||
var k = FROM_BLK_PREFIX + hash;
|
||||
var k2 = IN_BLK_PREFIX;
|
||||
// This is slow, but prevent us to create a new block->tx index.
|
||||
db.createReadStream({start: k, end: k + '~'})
|
||||
.on('data', function (data) {
|
||||
var ks = data.key.split('-');
|
||||
toChange.push({
|
||||
key: k2 + ks[2] + '-' + ks[1],
|
||||
type: 'put',
|
||||
value: isMain?1:0,
|
||||
});
|
||||
})
|
||||
.on('error', function (err) {
|
||||
return cb(err);
|
||||
})
|
||||
.on('end', function (err) {
|
||||
if (err) return cb(err);
|
||||
console.log('\t%s %d Txs', isMain?'Confirming':'Invalidating',toChange.length);
|
||||
db.batch(toChange, cb);
|
||||
});
|
||||
};
|
||||
|
||||
// txs can be a [hashes] or [txObjects]
|
||||
TransactionDb.prototype.createFromArray = function(txs, blockHash, next) {
|
||||
var self = this;
|
||||
|
||||
if (!txs) return next();
|
||||
|
||||
// TODO
|
||||
var insertedTxs = [];
|
||||
var updatedAddrs = {};
|
||||
var updatedAddrs = []; // TODO
|
||||
|
||||
async.forEachLimit(txs, CONCURRENCY, function(t, each_cb) {
|
||||
if (typeof t === 'string') {
|
||||
|
@ -387,32 +474,19 @@ function spec(b) {
|
|||
TransactionRpc.getRpcInfo(t, function(err, inInfo) {
|
||||
if (!inInfo) return each_cb(err);
|
||||
|
||||
self.add(inInfo, function(err) {
|
||||
if (err || !blockHash) return each_cb(err);
|
||||
|
||||
db.put(ROOT + t + '-' + blockHash, 1, function(err) {
|
||||
return each_cb(err);
|
||||
});
|
||||
});
|
||||
return self.add(inInfo, blockHash, each_cb);
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.add(t, function(err) {
|
||||
if (err) return each_cb(err);
|
||||
|
||||
db.put(ROOT + t.txid + '-' + blockHash, 1, function(err) {
|
||||
return each_cb(err);
|
||||
});
|
||||
});
|
||||
return self.add(t, blockHash, each_cb);
|
||||
}
|
||||
},
|
||||
function(err) {
|
||||
return next(err, insertedTxs, updatedAddrs);
|
||||
});
|
||||
};
|
||||
return next(err, updatedAddrs);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// txs can be a [hashes] or [txObjects]
|
||||
TransactionDb.prototype.createFromBlock = function(b, next) {
|
||||
var self = this;
|
||||
if (!b || !b.tx) return next();
|
||||
|
|
|
@ -7,8 +7,8 @@ function spec(b) {
|
|||
var RpcClient = require('bitcore/RpcClient').class(),
|
||||
// networks = require('bitcore/network'),
|
||||
BitcoreTransaction = require('bitcore/Transaction').class(),
|
||||
BitcoreBlock = require('bitcore/Block').class(),
|
||||
util = require('bitcore/util/util'),
|
||||
// BitcoreBlock = require('bitcore/Block').class(),
|
||||
// util = require('bitcore/util/util'),
|
||||
config = require('../config/config');
|
||||
|
||||
var rpc = b.rpc || new RpcClient(config.bitcoind);
|
||||
|
@ -24,10 +24,6 @@ function spec(b) {
|
|||
// Inputs
|
||||
if (tx.isCoinBase()) {
|
||||
info.isCoinBase = true;
|
||||
|
||||
var reward = BitcoreBlock.getBlockValue(info.height) / util.COIN;
|
||||
info.vin[0].reward = reward;
|
||||
info.valueIn = reward;
|
||||
}
|
||||
|
||||
var n =0;
|
||||
|
|
|
@ -31,10 +31,8 @@ function($scope, $rootScope, $routeParams, $location, Global, Address, getSocket
|
|||
var socket = getSocket($scope);
|
||||
socket.emit('subscribe', $routeParams.addrStr);
|
||||
socket.on($routeParams.addrStr, function(tx) {
|
||||
console.log('atx ' + tx.txid);
|
||||
var beep = new Audio('/sound/transaction.mp3');
|
||||
beep.play();
|
||||
$rootScope.$broadcast('tx', tx.txid);
|
||||
console.log('AddressTx event received ' + tx);
|
||||
$rootScope.$broadcast('tx', tx);
|
||||
});
|
||||
|
||||
$scope.params = $routeParams;
|
||||
|
|
|
@ -16,6 +16,14 @@ angular.module('insight.blocks').controller('BlocksController',
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
$scope.humanSince = function(time) {
|
||||
var m = moment.unix(time).startOf('day');
|
||||
var b = moment().startOf('day');
|
||||
return m.max().from(b);
|
||||
};
|
||||
|
||||
|
||||
$scope.list = function() {
|
||||
$scope.loading = true;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ angular.module('insight.system').controller('HeaderController',
|
|||
};
|
||||
|
||||
socket.on('block', function(block) {
|
||||
var blockHash = block.hash.toString();
|
||||
var blockHash = block.toString();
|
||||
console.log('Updated Blocks Height!');
|
||||
_getBlock(blockHash);
|
||||
});
|
||||
|
|
|
@ -4,9 +4,18 @@ var TRANSACTION_DISPLAYED = 5;
|
|||
var BLOCKS_DISPLAYED = 5;
|
||||
|
||||
angular.module('insight.system').controller('IndexController',
|
||||
function($scope, $rootScope, Global, getSocket, Blocks, Block, Transactions, Transaction) {
|
||||
function($scope, $rootScope, Global, getSocket, Blocks, Transaction) {
|
||||
$scope.global = Global;
|
||||
|
||||
var _getBlocks = function() {
|
||||
Blocks.get({
|
||||
limit: BLOCKS_DISPLAYED
|
||||
}, function(res) {
|
||||
$scope.blocks = res.blocks;
|
||||
$scope.blocksLength = res.lenght;
|
||||
});
|
||||
};
|
||||
|
||||
var _getTransaction = function(txid, cb) {
|
||||
Transaction.get({
|
||||
txId: txid
|
||||
|
@ -15,14 +24,6 @@ angular.module('insight.system').controller('IndexController',
|
|||
});
|
||||
};
|
||||
|
||||
var _getBlock = function(hash) {
|
||||
Block.get({
|
||||
blockHash: hash
|
||||
}, function(res) {
|
||||
$scope.blocks.unshift(res);
|
||||
});
|
||||
};
|
||||
|
||||
var socket = getSocket($scope);
|
||||
socket.emit('subscribe', 'inv');
|
||||
|
||||
|
@ -32,7 +33,7 @@ angular.module('insight.system').controller('IndexController',
|
|||
socket.on('tx', function(tx) {
|
||||
console.log('Transaction received! ' + JSON.stringify(tx));
|
||||
|
||||
var txStr = tx.txid.toString();
|
||||
var txStr = tx.toString();
|
||||
_getTransaction(txStr, function(res) {
|
||||
$scope.txs.unshift(res);
|
||||
if (parseInt($scope.txs.length, 10) >= parseInt(TRANSACTION_DISPLAYED, 10)) {
|
||||
|
@ -42,13 +43,9 @@ angular.module('insight.system').controller('IndexController',
|
|||
});
|
||||
|
||||
socket.on('block', function(block) {
|
||||
var blockHash = block.hash.toString();
|
||||
console.log('Block received! ' + JSON.stringify(block));
|
||||
if (parseInt($scope.blocks.length, 10) > parseInt(BLOCKS_DISPLAYED, 10) - 1) {
|
||||
$scope.blocks.pop();
|
||||
}
|
||||
|
||||
_getBlock(blockHash);
|
||||
var blockHash = block.toString();
|
||||
console.log('Block received! ' + JSON.stringify(blockHash));
|
||||
_getBlocks();
|
||||
});
|
||||
|
||||
$scope.humanSince = function(time) {
|
||||
|
@ -57,18 +54,7 @@ angular.module('insight.system').controller('IndexController',
|
|||
};
|
||||
|
||||
$scope.index = function() {
|
||||
Blocks.get({
|
||||
limit: BLOCKS_DISPLAYED
|
||||
}, function(res) {
|
||||
$scope.blocks = res.blocks;
|
||||
$scope.blocksLength = res.lenght;
|
||||
});
|
||||
|
||||
Transactions.get({
|
||||
limit: TRANSACTION_DISPLAYED
|
||||
}, function(res) {
|
||||
$scope.txs = res.txs;
|
||||
});
|
||||
_getBlocks();
|
||||
};
|
||||
|
||||
$scope.txs = [];
|
||||
|
|
|
@ -47,6 +47,11 @@
|
|||
<td> <strong> Height </strong></td>
|
||||
<td class="text-right text-muted">{{block.height}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> <strong> Block Reward </strong></td>
|
||||
<td class="text-right text-muted">{{$root.currency.getConvertion(block.reward)}}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> <strong> Timestamp </strong></td>
|
||||
<td class="text-right text-muted">{{block.time * 1000 | date:'medium'}}</td>
|
||||
|
|
|
@ -8,10 +8,15 @@
|
|||
<h3>Blocks <br> mined on:</h3>
|
||||
</div>
|
||||
</div>
|
||||
<p class="lead text-center m20v">{{pagination.current}}</p>
|
||||
<p class="lead text-center m20v">{{pagination.current}} UTC</p>
|
||||
<p class="lead text-center m20v" data-ng-show="loading"> </p>
|
||||
<p class="text-center m20v" data-ng-show="pagination.isToday && !loading">Today</p>
|
||||
<p class="text-center m20v" data-ng-show="!pagination.isToday && !loading">{{humanSince(pagination.currentTs)}}
|
||||
<p class="text-center m20v" data-ng-show="loading"> </p>
|
||||
|
||||
<div class="m50v text-center">
|
||||
<a class="btn btn-primary" href="/blocks-date/{{pagination.prev}}"><small>← {{pagination.prev}}</small></a>
|
||||
<a class="btn btn-primary" href="/blocks-date/{{pagination.next}}" data-ng-disabled="pagination.isToday"><small>{{pagination.next}} →</small></a>
|
||||
<a class="btn btn-primary" href="/blocks-date/{{pagination.next}}" data-ng-show="!pagination.isToday"><small>{{pagination.next}} →</small></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-9 col-md-offset-3">
|
||||
|
|
|
@ -31,9 +31,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<h2> About </h2>
|
||||
<p class="text-muted">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quas, sint, neque harum libero eos maiores rerum rem fuga quae architecto ea incidunt dolore optio ullam sit placeat vero perferendis beatae?</p>
|
||||
<p class="text-muted">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, unde quidem commodi dolor asperiores ullam molestias sit a sapiente ipsa!</p>
|
||||
<p class="text-muted">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt tempora fugiat dolorem cupiditate perspiciatis praesentium.</p>
|
||||
<p class="text-muted">Insight is a bitcoin blockchain API for writing web wallets and other apps that need more advanced blockchain queries than provided by bitcoind RPC. Check out the <a href="http://github.com/bitpay/insight">source code</a>.</p>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-4 col-gray">
|
||||
|
@ -48,43 +46,16 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-show="!txs.length"><td colspan="5">Waiting for transactions...</td></tr>
|
||||
<tr data-ng-show="!txs.length"><td colspan="3">Waiting for transactions...</td></tr>
|
||||
<tr class="fader" data-ng-repeat='tx in txs'>
|
||||
<td>
|
||||
<a class="ellipsis" href="/tx/{{tx.txid}}">{{tx.txid}}</a>
|
||||
</td>
|
||||
<td><span class="ellipsis">{{humanSince(tx.time)}}</span></td>
|
||||
<td>{{tx.valueOut}}</td>
|
||||
<td><span class="ellipsis">{{tx.valueOut}}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3> Other Bitcoin Links </h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="">Most Popular Addresses</a>
|
||||
<small> - Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolores.</small>
|
||||
</li>
|
||||
<li>
|
||||
<a href="">Addresses</a>
|
||||
<small> - Addresses which have received the most payments</small>
|
||||
</li>
|
||||
<li>
|
||||
<a href="">Lorem ipsum dolor.</a>
|
||||
<small> - Lorem ipsum dolor sit amet.</small>
|
||||
</li>
|
||||
<li>
|
||||
<a href="">Most Popular Addresses</a>
|
||||
<small> - Addresses which have received the most payments</small>
|
||||
</li>
|
||||
<li>
|
||||
<a href="">Lorem ipsum dolor sit.</a>
|
||||
<small> - Lorem ipsum dolor sit amet, consectetur adipisicing.</small>
|
||||
</li>
|
||||
<li>
|
||||
<a href="">Addresses</a>
|
||||
<small> - Addresses which have received the most payments</small>
|
||||
</li>
|
||||
</ul>
|
||||
</div> <!-- END OF COL-3 -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
<tr>
|
||||
<td>Skipped Blocks (previously synced)</td>
|
||||
<td class="text-right">{{sync.skippedBlocks}}</td>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -80,9 +81,14 @@
|
|||
<table class="table" style="table-layout: fixed" data-ng-controller="StatusController" data-ng-init="getStatus('LastBlockHash')">
|
||||
<thead data-ng-include src="'/views/includes/infoStatus.html'"> </thead>
|
||||
<tr>
|
||||
<td>Last Block Hash</td>
|
||||
<td>Last Block Hash (Bitcoind)</td>
|
||||
<td class="text-right ellipsis"><a href="/block/{{lastblockhash}}">{{lastblockhash}}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current Blockchain Tip(Insight)</td>
|
||||
<td class="text-right ellipsis"><a href="/block/{{syncTipHash}}">{{syncTipHash}}</a></td>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div> <!-- END OF COL-8 -->
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<div class="col-md-5">
|
||||
<div class="row" data-ng-show="tx.isCoinBase">
|
||||
<div class="col-md-12 transaction-vin-vout" data-ng-repeat="vin in tx.vin">
|
||||
<div class="text-muted pull-right btc-value"><small>{{$root.currency.getConvertion(vin.reward)}}</small></div>
|
||||
<div class="ellipsis">
|
||||
<span>No Inputs (Newly Generated Coins)</span>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,548 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
|
||||
var
|
||||
assert = require('assert'),
|
||||
async = require('async'),
|
||||
HistoricSync = require('../../lib/HistoricSync').class();
|
||||
|
||||
|
||||
var s;
|
||||
var b = [
|
||||
'00000000c4cbd75af741f3a2b2ff72d9ed4d83a048462c1efe331be31ccf006b', //0 B#16
|
||||
'00000000fe198cce4c8abf9dca0fee1182cb130df966cc428ad2a230df8da743', //1
|
||||
'000000008d55c3e978639f70af1d2bf1fe6f09cb3143e104405a599215c89a48', //2
|
||||
'000000009b3bca4909f38313f2746120129cce4a699a1f552390955da470c5a9', //3
|
||||
'00000000ede57f31cc598dc241d129ccb4d8168ef112afbdc870dc60a85f5dd3', //4 B#20
|
||||
];
|
||||
var t = [
|
||||
'd08582d3711f75d085c618874fb0d049ae09d5ec95ec6f5abd289f4b54712c54', // TX from B#16
|
||||
'1729001087e0cebea8d14de1653d5cf59628d9746bc1ae65f776f1cbaff7ebad', //1
|
||||
'cf53d7ccd83a099acfbc319ee10c1e3b10e3d42ba675b569fdd6b69cb8d2db4e', //2
|
||||
'73a4988adf462b6540cfa59097804174b298cfa439f73c1a072c2c6fbdbe57c7', //3
|
||||
'd45f9da73619799e9d7bd03cc290e70875ea4cbad56b8bffa15135fbbb3df9ea', //4 Tx from B20
|
||||
];
|
||||
|
||||
var test = function(cb) {
|
||||
async.each([2,3,4], function(i,c) {
|
||||
s.sync.bDb.getPrev(b[i], function(err, p) {
|
||||
assert.equal(p,b[i-1]);
|
||||
return c();
|
||||
});
|
||||
}, function() {
|
||||
async.each([0,1,2,3,4], function(i,c) {
|
||||
s.sync.bDb.has(b[i], function(err, p) {
|
||||
assert(p);
|
||||
return c();
|
||||
});
|
||||
}, function() {
|
||||
async.each([0,1,2,3], function(i,c) {
|
||||
s.sync.bDb.getNext(b[i], function(err, p) {
|
||||
assert.equal(p,b[i+1]);
|
||||
return c();
|
||||
});
|
||||
}, cb);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* TEST CASES
|
||||
*
|
||||
* Blocks: 0-1-2-3-4
|
||||
* case 1)
|
||||
* 0-1-2-3-4
|
||||
* \
|
||||
* C1*
|
||||
*
|
||||
* case 2)
|
||||
* 0-1-2---3-4
|
||||
* \ \
|
||||
* C1 C2*
|
||||
*
|
||||
* case 2b)
|
||||
* 0-1-2---3-4
|
||||
* \ \
|
||||
* C1 C2-C2b(TX=C1.TX)*
|
||||
* case 2c)
|
||||
* 0-1-2---3-4
|
||||
* \ \
|
||||
* C1 C2-C2b(TX=C1.TX)
|
||||
* \
|
||||
* C2c(TX=C2.TX)*
|
||||
*
|
||||
*/
|
||||
|
||||
describe('Sync Reorgs', function(){
|
||||
|
||||
before(function(done) {
|
||||
s = new HistoricSync();
|
||||
s.init({}, function(err) {
|
||||
if (err) return done(err);
|
||||
s.sync.destroy(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('simple RPC forward syncing', function(done) {
|
||||
s.getPrevNextBlock(s.genesis,b[4], {
|
||||
next: true,
|
||||
}, function(err) {
|
||||
if (err) return done(err);
|
||||
test(done);
|
||||
});
|
||||
});
|
||||
|
||||
var case1 = {
|
||||
hash: '0000000000000000000000000000000000000000000000000000000000000001',
|
||||
tx: [ 'f0596531810160d090813673b4a397f4617aab44eb26c7f06c8a766eac984b91' ],
|
||||
time: 1296690099,
|
||||
previousblockhash: b[2],
|
||||
};
|
||||
|
||||
|
||||
it('reorg, case 1', function(done) {
|
||||
async.series([
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[3], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[4], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.storeTipBlock(case1, function(err) {
|
||||
assert(!err, 'shouldnt return error' + err);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.isMain(b[2], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.isMain(b[3], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is, b[3] + 'should not be on main chain');
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.isMain(b[4], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[3], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[4], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case1.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
], done );
|
||||
});
|
||||
|
||||
it('reorg, case 1 (repeat)', function(done) {
|
||||
s.sync.storeTipBlock(case1, function(err) {
|
||||
assert(!err, 'shouldnt return error' + err);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
var case2 = {
|
||||
hash: '0000000000000000000000000000000000000000000000000000000000000002',
|
||||
tx: [ '99bb359a4b12a588fcb9e59e5e8d92d593ce7a56d2ba42085fe86d9a0b4fde15' ],
|
||||
time: 1296690099,
|
||||
previousblockhash: b[3],
|
||||
};
|
||||
|
||||
|
||||
it('reorg, case 2', function(done) {
|
||||
async.series([
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case1.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[4], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.storeTipBlock(case2, function(err) {
|
||||
assert(!err, 'shouldnt return error' + err);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.isMain(b[3], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.isMain(b[4], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is, b[3] + 'should not be on main chain');
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.isMain(case1.hash, function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.isMain(case2.hash, function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[3], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is, 'transaction t[3] should be valid:' + t[3]);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case1.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case2.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[4], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.getNext(b[2], function(err, val) {
|
||||
assert(!err);
|
||||
assert.equal(val,b[3]);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
], done );
|
||||
});
|
||||
|
||||
|
||||
var case2b = {
|
||||
hash: '0000000000000000000000000000000000000000000000000000000000000003',
|
||||
tx: case1.tx,
|
||||
time: 1296690099,
|
||||
previousblockhash: case2.hash,
|
||||
};
|
||||
|
||||
it('reorg, case 2b', function(done) {
|
||||
async.series([
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case2b.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.storeTipBlock(case2b, function(err) {
|
||||
assert(!err, 'shouldnt return error' + err);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[3], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is, 'transaction t[3] should be valid:' + t[3]);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case2b.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
], done );
|
||||
});
|
||||
|
||||
|
||||
|
||||
var case2c = {
|
||||
hash: '0000000000000000000000000000000000000000000000000000000000000004',
|
||||
tx: case2.tx,
|
||||
time: 1296690099,
|
||||
previousblockhash: case1.hash,
|
||||
};
|
||||
|
||||
it('reorg, case 2c', function(done) {
|
||||
async.series([
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case1.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.isMain(case1.hash, function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is, 'case1 block shouldnt be main:' + case1.hash);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case2c.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is); //It was there before (from case2)
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.storeTipBlock(case2c, function(err) {
|
||||
assert(!err, 'shouldnt return error' + err);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case1.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.has(case1.hash, function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.has(case2c.hash, function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case2c.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[3], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is, 'TX t[3]: shouldnt be confirmed:' + t[3] +':'+ is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[4], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case2.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
|
||||
], done );
|
||||
});
|
||||
|
||||
var case3 = {
|
||||
hash: '0000000000000000000000000000000000000000000000000000000000000005',
|
||||
tx: case2.tx,
|
||||
time: 1296690099,
|
||||
previousblockhash: '666',
|
||||
};
|
||||
|
||||
it('reorg, case 3)', function(done) {
|
||||
async.series([
|
||||
function (c) {
|
||||
s.sync.storeTipBlock(case3, function(err) {
|
||||
assert(!err, 'shouldnt return error' + err);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
|
||||
//shoudnt change anything
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case1.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.has(case1.hash, function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.has(case2c.hash, function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case2c.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[3], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is, 'TX t[3]: shouldnt be confirmed:' + t[3] +':'+ is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(t[4], function(err,is) {
|
||||
assert(!err);
|
||||
assert(!is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(case2.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
|
||||
], done );
|
||||
});
|
||||
|
||||
var p2p = {
|
||||
hash: '0000000000000000000000000000000000000000000000000000000000000006',
|
||||
tx: ['f6c2901f39fd07f2f2e503183d76f73ecc1aee9ac9216fde58e867bc29ce674e'],
|
||||
time: 1296690099,
|
||||
previousblockhash: '111',
|
||||
};
|
||||
|
||||
it('p2p, no reorg allowed', function(done) {
|
||||
async.series([
|
||||
function (c) {
|
||||
s.sync.storeTipBlock(p2p, false, function(err) {
|
||||
assert(!err, 'shouldnt return error' + err);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.has(p2p.hash, function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.txDb.isConfirmed(p2p.tx[0], function(err,is) {
|
||||
assert(!err);
|
||||
assert(is);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.getNext(p2p.hash, function(err,v) {
|
||||
assert(!err);
|
||||
assert.equal(v,p2p.nextblockhash);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
function (c) {
|
||||
s.sync.bDb.getNext(p2p.previousblockhash, function(err,v) {
|
||||
assert(!err);
|
||||
assert.equal(v,p2p.hash);
|
||||
return c();
|
||||
});
|
||||
},
|
||||
|
||||
], done );
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -37,14 +37,15 @@
|
|||
},
|
||||
{
|
||||
"addr": "mgqvRGJMwR9JU5VhJ3x9uX9MTkzTsmmDgQ",
|
||||
"txApperances": 27,
|
||||
"balance": 5.1
|
||||
"txApperances": 28,
|
||||
"balance": 0,
|
||||
"totalReceived": 54.81284116
|
||||
},
|
||||
{
|
||||
"addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29",
|
||||
"txApperances": 6033,
|
||||
"balance": 1049.69744101,
|
||||
"totalReceived": 1049.69744101,
|
||||
"txApperances": 6046,
|
||||
"balance": 1149.19744101,
|
||||
"totalReceived": 1149.19744101,
|
||||
"totalSent": 0
|
||||
},
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ var TESTING_BLOCK = '000000000185678d3d7ecc9962c96418174431f93fe20bf216d55652724
|
|||
|
||||
var
|
||||
assert = require('assert'),
|
||||
config = require('../../config/config'),
|
||||
// config = require('../../config/config'),
|
||||
BlockDb = require('../../lib/BlockDb').class();
|
||||
|
||||
var bDb;
|
||||
|
@ -36,22 +36,5 @@ describe('BlockDb fromHashWithInfo', function(){
|
|||
done();
|
||||
});
|
||||
});
|
||||
it('setOrphan', function(done) {
|
||||
var b16 = '00000000c4cbd75af741f3a2b2ff72d9ed4d83a048462c1efe331be31ccf006b';
|
||||
var b17 = '00000000fe198cce4c8abf9dca0fee1182cb130df966cc428ad2a230df8da743';
|
||||
|
||||
bDb.has(b17, function(err, has) {
|
||||
assert(has);
|
||||
bDb.setOrphan(b17, function(err, oldPrev) {
|
||||
assert.equal(oldPrev, b16);
|
||||
bDb.setPrev(b17, b16, function(err, oldPrev) {
|
||||
bDb.getPrev(b17, function(err, p) {
|
||||
assert.equal(p, b16);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
var TESTING_BLOCK0 = '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943';
|
||||
var TESTING_BLOCK1 = '00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206';
|
||||
var TESTING_BLOCK0 = '00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206';
|
||||
var TESTING_BLOCK1 = '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943';
|
||||
var START_TS = 1;
|
||||
var END_TS = '1296688928~'; // 2/2/2011 23:23PM
|
||||
var LIMIT = 2;
|
||||
|
||||
var assert = require('assert'),
|
||||
BlockDb = require('../../lib/BlockDb').class();
|
||||
|
@ -24,7 +23,7 @@ describe('BlockDb getBlocksByDate', function(){
|
|||
|
||||
it('Get Hash by Date', function(done) {
|
||||
|
||||
bDb.getBlocksByDate(START_TS, END_TS, LIMIT, function(err, list) {
|
||||
bDb.getBlocksByDate(START_TS, END_TS, function(err, list) {
|
||||
if (err) done(err);
|
||||
assert(list, 'returns list');
|
||||
assert.equal(list.length,2, 'list has 2 items');
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
|
||||
var
|
||||
assert = require('assert'),
|
||||
async = require('async'),
|
||||
Sync = require('../../lib/Sync').class();
|
||||
|
||||
|
||||
var b = [
|
||||
'00000000c4cbd75af741f3a2b2ff72d9ed4d83a048462c1efe331be31ccf006b', //B#16
|
||||
'00000000fe198cce4c8abf9dca0fee1182cb130df966cc428ad2a230df8da743',
|
||||
'000000008d55c3e978639f70af1d2bf1fe6f09cb3143e104405a599215c89a48',
|
||||
'000000009b3bca4909f38313f2746120129cce4a699a1f552390955da470c5a9',
|
||||
'00000000ede57f31cc598dc241d129ccb4d8168ef112afbdc870dc60a85f5dd3', //B#20
|
||||
];
|
||||
|
||||
var fix = function(s,cb) {
|
||||
async.each([1,2,3,4], function(i,c) {
|
||||
s.bDb.setPrev(b[i],b[i-1], function() {
|
||||
return c();
|
||||
});
|
||||
}, cb);
|
||||
};
|
||||
|
||||
var test = function(s,cb) {
|
||||
async.each([2,3,4], function(i,c) {
|
||||
s.bDb.getPrev(b[i], function(err, p) {
|
||||
assert.equal(p,0);
|
||||
return c();
|
||||
});
|
||||
}, function() {
|
||||
s.bDb.getPrev(b[1], function(err, p) {
|
||||
assert.equal(p,b[0]);
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
var testNo = function(s,cb) {
|
||||
async.each([2,3,4], function(i,c) {
|
||||
s.bDb.getPrev(b[i], function(err, p) {
|
||||
assert.equal(p,b[i-1]);
|
||||
return c();
|
||||
});
|
||||
}, function() {
|
||||
s.bDb.getPrev(b[1], function(err, p) {
|
||||
assert.equal(p,b[0]);
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
var s;
|
||||
describe('Sync checkOrphan', function(){
|
||||
|
||||
before(function(done) {
|
||||
s = new Sync();
|
||||
fix(s,done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
|
||||
fix(s,function() {
|
||||
s.close(done);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('checkOrphan', function(done) {
|
||||
this.timeout(100000);
|
||||
|
||||
s.bDb.has(b[0], function(err, has) {
|
||||
assert(has);
|
||||
s.bDb.has(b[1], function(err, has) {
|
||||
assert(has);
|
||||
s.checkOrphan(b[4],b[1], function() {
|
||||
testNo(s,done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
10
util/p2p.js
10
util/p2p.js
|
@ -11,10 +11,16 @@ var program = require('commander');
|
|||
program
|
||||
.version(PROGRAM_VERSION)
|
||||
.option('-N --network [testnet]', 'Set bitcoin network [testnet]', 'testnet')
|
||||
.option('-V --verbose', 'Verbose', 1)
|
||||
.parse(process.argv);
|
||||
|
||||
var ps = new PeerSync();
|
||||
ps.init(program);
|
||||
ps.run();
|
||||
ps.init(program, function(err){
|
||||
if (err) {
|
||||
console.log(err);
|
||||
process.exit(1);
|
||||
}
|
||||
ps.run();
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ program
|
|||
.option('-R --reverse', 'Sync backwards', 0)
|
||||
.option('-U --uptoexisting', 'Sync only until an existing block is found', 0)
|
||||
.option('-F --fromfiles', 'Sync using bitcoind .dat block files (faster)', 0)
|
||||
.option('-v --verbose', 'Verbose 0/1', 0)
|
||||
.parse(process.argv);
|
||||
|
||||
var historicSync = new HistoricSync();
|
||||
|
|
Loading…
Reference in New Issue