Merge pull request #13 from matiu/feature/use-soop

Feature/use soop
This commit is contained in:
Mario Colque 2014-03-10 16:42:47 -02:00
commit 05d8b7c76a
29 changed files with 2109 additions and 2189 deletions

View File

@ -5,7 +5,7 @@
*/ */
var common = require('./common'), var common = require('./common'),
async = require('async'), async = require('async'),
BlockDb = require('../../lib/BlockDb').class(); BlockDb = require('../../lib/BlockDb');
var bdb = new BlockDb(); var bdb = new BlockDb();

View File

@ -17,7 +17,7 @@ exports.show = function(req, res) {
} }
else { else {
var option = req.query.q; var option = req.query.q;
var statusObject = Status.new(); var statusObject = new Status();
var returnJsonp = function (err) { var returnJsonp = function (err) {
if (err || ! statusObject) if (err || ! statusObject)

View File

@ -7,12 +7,10 @@ var Address = require('../models/Address');
var async = require('async'); var async = require('async');
var common = require('./common'); var common = require('./common');
var TransactionDb = require('../../lib/TransactionDb').class(); var Rpc = require('../../lib/Rpc');
var BlockDb = require('../../lib/BlockDb').class();
var Rpc = require('../../lib/Rpc').class();
var tDb = new TransactionDb(); var tDb = require('../../lib/TransactionDb').default();
var bdb = new BlockDb(); var bdb = require('../../lib/BlockDb').default();
exports.send = function(req, res) { exports.send = function(req, res) {
Rpc.sendRawTransaction(req.body.rawtx, function(err, txid) { Rpc.sendRawTransaction(req.body.rawtx, function(err, txid) {

View File

@ -1,19 +1,16 @@
'use strict'; 'use strict';
require('classtool'); var imports = require('soop').imports();
var async = require('async');
var BitcoreAddress = require('bitcore/Address');
var BitcoreTransaction = require('bitcore/Transaction');
var BitcoreUtil = require('bitcore/util/util');
var Parser = require('bitcore/util/BinaryParser');
var Buffer = require('buffer').Buffer;
var TransactionDb = imports.TransactionDb || require('../../lib/TransactionDb').default();
var CONCURRENCY = 5;
function Address(addrStr) {
function spec() {
var async = require('async');
var BitcoreAddress = require('bitcore/Address').class();
var BitcoreUtil = require('bitcore/util/util');
var TransactionDb = require('../../lib/TransactionDb').class();
var BitcoreTransaction = require('bitcore/Transaction').class();
var Parser = require('bitcore/util/BinaryParser').class();
var Buffer = require('buffer').Buffer;
var CONCURRENCY = 5;
function Address(addrStr) {
this.balanceSat = 0; this.balanceSat = 0;
this.totalReceivedSat = 0; this.totalReceivedSat = 0;
this.totalSentSat = 0; this.totalSentSat = 0;
@ -71,23 +68,23 @@ function spec() {
enumerable: 1, enumerable: 1,
}); });
} }
Address.prototype._getScriptPubKey = function(hex,n) { Address.prototype._getScriptPubKey = function(hex,n) {
// ScriptPubKey is not provided by bitcoind RPC, so we parse it from tx hex. // ScriptPubKey is not provided by bitcoind RPC, so we parse it from tx hex.
var parser = new Parser(new Buffer(hex,'hex')); var parser = new Parser(new Buffer(hex,'hex'));
var tx = new BitcoreTransaction(); var tx = new BitcoreTransaction();
tx.parse(parser); tx.parse(parser);
return (tx.outs[n].s.toString('hex')); return (tx.outs[n].s.toString('hex'));
}; };
Address.prototype.getUtxo = function(next) { Address.prototype.getUtxo = function(next) {
var self = this; var self = this;
if (!self.addrStr) return next(); if (!self.addrStr) return next();
var ret = []; var ret = [];
var db = new TransactionDb(); var db = TransactionDb;
db.fromAddr(self.addrStr, function(err,txOut){ db.fromAddr(self.addrStr, function(err,txOut){
if (err) return next(err); if (err) return next(err);
@ -96,11 +93,11 @@ function spec() {
async.eachLimit(txOut,CONCURRENCY,function (txItem, a_c) { async.eachLimit(txOut,CONCURRENCY,function (txItem, a_c) {
db.fromIdInfoSimple(txItem.txid, function(err, info) { db.fromIdInfoSimple(txItem.txid, function(err, info) {
var scriptPubKey = self._getScriptPubKey(info.hex, txItem.index);
// we are filtering out even unconfirmed spents! // we are filtering out even unconfirmed spents!
// add || !txItem.spentIsConfirmed // add || !txItem.spentIsConfirmed
if (!txItem.spentTxId) {
if (!txItem.spentTxId && info && info.hex) {
var scriptPubKey = self._getScriptPubKey(info.hex, txItem.index);
ret.push({ ret.push({
address: self.addrStr, address: self.addrStr,
txid: txItem.txid, txid: txItem.txid,
@ -117,14 +114,14 @@ function spec() {
return next(err,ret); return next(err,ret);
}); });
}); });
}; };
Address.prototype.update = function(next) { Address.prototype.update = function(next) {
var self = this; var self = this;
if (!self.addrStr) return next(); if (!self.addrStr) return next();
var txs = []; var txs = [];
var db = new TransactionDb(); var db = TransactionDb;
async.series([ async.series([
function (cb) { function (cb) {
var seen={}; var seen={};
@ -186,9 +183,7 @@ function spec() {
self.transactions = txs.map(function(i) { return i.txid; } ); self.transactions = txs.map(function(i) { return i.txid; } );
return next(err); return next(err);
}); });
}; };
return Address; module.exports = require('soop')(Address);
}
module.defineClass(spec);

View File

@ -1,19 +1,16 @@
'use strict'; 'use strict';
//var imports = require('soop').imports();
require('classtool'); var async = require('async');
var RpcClient = require('bitcore/RpcClient');
var config = require('../../config/config');
var rpc = new RpcClient(config.bitcoind);
function spec() { function Status() {
var async = require('async'); this.bDb = require('../../lib/BlockDb').default();
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() { Status.prototype.getInfo = function(next) {
this.bDb = new BlockDb();
}
Status.prototype.getInfo = function(next) {
var that = this; var that = this;
async.series([ async.series([
function (cb) { function (cb) {
@ -27,9 +24,9 @@ function spec() {
], function (err) { ], function (err) {
return next(err); return next(err);
}); });
}; };
Status.prototype.getDifficulty = function(next) { Status.prototype.getDifficulty = function(next) {
var that = this; var that = this;
async.series([ async.series([
function (cb) { function (cb) {
@ -43,9 +40,9 @@ function spec() {
], function (err) { ], function (err) {
return next(err); return next(err);
}); });
}; };
Status.prototype.getTxOutSetInfo = function(next) { Status.prototype.getTxOutSetInfo = function(next) {
var that = this; var that = this;
async.series([ async.series([
function (cb) { function (cb) {
@ -59,9 +56,9 @@ function spec() {
], function (err) { ], function (err) {
return next(err); return next(err);
}); });
}; };
Status.prototype.getBestBlockHash = function(next) { Status.prototype.getBestBlockHash = function(next) {
var that = this; var that = this;
async.series([ async.series([
function (cb) { function (cb) {
@ -76,9 +73,9 @@ function spec() {
], function (err) { ], function (err) {
return next(err); return next(err);
}); });
}; };
Status.prototype.getLastBlockHash = function(next) { Status.prototype.getLastBlockHash = function(next) {
var that = this; var that = this;
that.bDb.getTip(function(err,tip) { that.bDb.getTip(function(err,tip) {
that.syncTipHash = tip; that.syncTipHash = tip;
@ -103,10 +100,6 @@ function spec() {
} }
); );
}); });
}; };
return Status;
}
module.defineClass(spec);
module.exports = require('soop')(Status);

View File

@ -5,7 +5,7 @@ var util = require('util');
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var RpcClient = require('../node_modules/bitcore/RpcClient').class(); var RpcClient = require('../node_modules/bitcore/RpcClient');
var config = require('../config/config'); var config = require('../config/config');

View File

@ -2,7 +2,7 @@
'use strict'; 'use strict';
var util = require('util'); var util = require('util');
var T = require('../lib/TransactionDb').class(); var T = require('../lib/TransactionDb');
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; process.env.NODE_ENV = process.env.NODE_ENV || 'development';

View File

@ -41,7 +41,7 @@ first 10%
=> sacando los contenidos adentro de getblock from file de => 4.5s!! => sacando los contenidos adentro de getblock from file de => 4.5s!!
=> con base58 cpp => 21s => con base58 cpp => 21s
=> toda la testnet => 17m => toda la testnet => 17m !!
10% de blk2 10% de blk2
=> 50s con base58cpp => 50s con base58cpp
@ -54,3 +54,7 @@ first 10%
=> 15s comentando desde b.getStandardizedObject() => 15s comentando desde b.getStandardizedObject()
=> 39s comentando dps b.getStandardizedObject() => 39s comentando dps b.getStandardizedObject()
Mon Mar 10 11:59:25 ART 2014
10% de blk 0 (testnet)
=> 37s

View File

@ -9,8 +9,8 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development';
*/ */
var express = require('express'), var express = require('express'),
fs = require('fs'), fs = require('fs'),
PeerSync = require('./lib/PeerSync').class(), PeerSync = require('./lib/PeerSync'),
HistoricSync = require('./lib/HistoricSync').class(); HistoricSync = require('./lib/HistoricSync');
//Initializing system variables //Initializing system variables
var config = require('./config/config'); var config = require('./config/config');

View File

@ -1,44 +1,38 @@
'use strict'; 'use strict';
var imports = require('soop').imports();
var ThisParent = imports.parent || require('events').EventEmitter;
var TIMESTAMP_PREFIX = 'bts-'; // b-ts-<ts> => <hash>
var PREV_PREFIX = 'bpr-'; // b-prev-<hash> => <prev_hash>
var NEXT_PREFIX = 'bne-'; // b-next-<hash> => <next_hash>
var MAIN_PREFIX = 'bma-'; // b-main-<hash> => 1/0
var TIP = 'bti-'; // last block on the chain
var LAST_FILE_INDEX = 'file-'; // last processed file index
require('classtool'); var MAX_OPEN_FILES = 500;
function spec(b) { /**
* Module dependencies.
var superclass = b.superclass || require('events').EventEmitter; */
var TIMESTAMP_PREFIX = 'bts-'; // b-ts-<ts> => <hash> var levelup = require('levelup'),
var PREV_PREFIX = 'bpr-'; // b-prev-<hash> => <prev_hash>
var NEXT_PREFIX = 'bne-'; // b-next-<hash> => <next_hash>
var MAIN_PREFIX = 'bma-'; // b-main-<hash> => 1/0
var TIP = 'bti-'; // last block on the chain
var LAST_FILE_INDEX = 'file-'; // last processed file index
var MAX_OPEN_FILES = 500;
/**
* Module dependencies.
*/
var levelup = require('levelup'),
config = require('../config/config'); config = require('../config/config');
var db = b.db || levelup(config.leveldb + '/blocks',{maxOpenFiles: MAX_OPEN_FILES} ); var db = imports.db || levelup(config.leveldb + '/blocks',{maxOpenFiles: MAX_OPEN_FILES} );
var Rpc = b.rpc || require('./Rpc').class(); var Rpc = imports.rpc || require('./Rpc');
var PoolMatch = b.poolMatch || require('./PoolMatch').class(config); var PoolMatch = imports.poolMatch || require('soop').load('./PoolMatch',config);
var TransactionDb = require('./TransactionDb.js').class(); var tDb = require('./TransactionDb.js').default();
var BlockDb = function() { var BlockDb = function() {
BlockDb.super(this, arguments); BlockDb.super(this, arguments);
this.poolMatch = new PoolMatch(); this.poolMatch = new PoolMatch();
}; };
BlockDb.parent = ThisParent;
BlockDb.superclass = superclass; BlockDb.prototype.close = function(cb) {
BlockDb.prototype.close = function(cb) {
db.close(cb); db.close(cb);
}; };
BlockDb.prototype.drop = function(cb) { BlockDb.prototype.drop = function(cb) {
var path = config.leveldb + '/blocks'; var path = config.leveldb + '/blocks';
db.close(function() { db.close(function() {
require('leveldown').destroy(path, function () { require('leveldown').destroy(path, function () {
@ -46,12 +40,12 @@ function spec(b) {
return cb(); return cb();
}); });
}); });
}; };
// adds a block. Does not update Next pointer in // adds a block. Does not update Next pointer in
// the block prev to the new block, nor TIP pointer // the block prev to the new block, nor TIP pointer
// //
BlockDb.prototype.add = function(b, cb) { BlockDb.prototype.add = function(b, cb) {
var self = this; var self = this;
var time_key = TIMESTAMP_PREFIX + var time_key = TIMESTAMP_PREFIX +
( b.time || Math.round(new Date().getTime() / 1000) ); ( b.time || Math.round(new Date().getTime() / 1000) );
@ -66,36 +60,36 @@ function spec(b) {
} }
cb(err); cb(err);
}); });
}; };
BlockDb.prototype.getTip = function(cb) { BlockDb.prototype.getTip = function(cb) {
db.get(TIP, function(err, val) { db.get(TIP, function(err, val) {
return cb(err,val); return cb(err,val);
}); });
}; };
BlockDb.prototype.setTip = function(hash, cb) { BlockDb.prototype.setTip = function(hash, cb) {
db.put(TIP, hash, function(err) { db.put(TIP, hash, function(err) {
return cb(err); return cb(err);
}); });
}; };
//mainly for testing //mainly for testing
BlockDb.prototype.setPrev = function(hash, prevHash, cb) { BlockDb.prototype.setPrev = function(hash, prevHash, cb) {
db.put(PREV_PREFIX + hash, prevHash, function(err) { db.put(PREV_PREFIX + hash, prevHash, function(err) {
return cb(err); return cb(err);
}); });
}; };
BlockDb.prototype.getPrev = function(hash, cb) { BlockDb.prototype.getPrev = function(hash, cb) {
db.get(PREV_PREFIX + hash, function(err,val) { db.get(PREV_PREFIX + hash, function(err,val) {
if (err && err.notFound) { err = null; val = null;} if (err && err.notFound) { err = null; val = null;}
return cb(err,val); return cb(err,val);
}); });
}; };
BlockDb.prototype.setLastFileIndex = function(idx, cb) { BlockDb.prototype.setLastFileIndex = function(idx, cb) {
var self = this; var self = this;
if (this.lastFileIndexSaved === idx) return cb(); if (this.lastFileIndexSaved === idx) return cb();
@ -103,42 +97,42 @@ function spec(b) {
self.lastFileIndexSaved = idx; self.lastFileIndexSaved = idx;
return cb(err); return cb(err);
}); });
}; };
BlockDb.prototype.getLastFileIndex = function(cb) { BlockDb.prototype.getLastFileIndex = function(cb) {
db.get(LAST_FILE_INDEX, function(err,val) { db.get(LAST_FILE_INDEX, function(err,val) {
if (err && err.notFound) { err = null; val = null;} if (err && err.notFound) { err = null; val = null;}
return cb(err,val); 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;}
return cb(err,val); return cb(err,val);
}); });
}; };
BlockDb.prototype.isMain = function(hash, cb) { BlockDb.prototype.isMain = function(hash, cb) {
db.get(MAIN_PREFIX + hash, function(err, val) { db.get(MAIN_PREFIX + hash, function(err, val) {
if (err && err.notFound) { err = null; val = 0;} if (err && err.notFound) { err = null; val = 0;}
return cb(err,parseInt(val)); return cb(err,parseInt(val));
}); });
}; };
BlockDb.prototype.setMain = function(hash, isMain, cb) { BlockDb.prototype.setMain = function(hash, isMain, cb) {
if (!isMain) console.log('\tNew orphan: %s',hash); if (!isMain) console.log('\tNew orphan: %s',hash);
db.put(MAIN_PREFIX + hash, isMain?1:0, function(err) { db.put(MAIN_PREFIX + hash, isMain?1:0, function(err) {
return cb(err); return cb(err);
}); });
}; };
BlockDb.prototype.setNext = function(hash, nextHash, cb) { BlockDb.prototype.setNext = function(hash, nextHash, cb) {
db.put(NEXT_PREFIX + hash, nextHash, function(err) { db.put(NEXT_PREFIX + hash, nextHash, function(err) {
return cb(err); return cb(err);
}); });
}; };
BlockDb.prototype.countConnected = function(cb) { BlockDb.prototype.countConnected = function(cb) {
var c = 0; var c = 0;
console.log('Counting connected blocks. This could take some minutes'); console.log('Counting connected blocks. This could take some minutes');
db.createReadStream({start: MAIN_PREFIX, end: MAIN_PREFIX + '~' }) db.createReadStream({start: MAIN_PREFIX, end: MAIN_PREFIX + '~' })
@ -151,10 +145,10 @@ function spec(b) {
.on('end', function () { .on('end', function () {
return cb(null, c); return cb(null, c);
}); });
}; };
// .has() return true orphans also // .has() return true orphans also
BlockDb.prototype.has = function(hash, cb) { BlockDb.prototype.has = function(hash, cb) {
var k = PREV_PREFIX + hash; var k = PREV_PREFIX + hash;
db.get(k, function (err) { db.get(k, function (err) {
var ret = true; var ret = true;
@ -164,13 +158,12 @@ function spec(b) {
} }
return cb(err, ret); return cb(err, ret);
}); });
}; };
BlockDb.prototype.getPoolInfo = function(tx, cb) { BlockDb.prototype.getPoolInfo = function(tx, cb) {
var tr = new TransactionDb();
var self = this; var self = this;
tr._getInfo(tx, function(e, a) { tDb._getInfo(tx, function(e, a) {
if (e) return cb(false); if (e) return cb(false);
if (a.isCoinBase) { if (a.isCoinBase) {
@ -180,9 +173,9 @@ function spec(b) {
return cb(aa); return cb(aa);
} }
}); });
}; };
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) {
@ -199,9 +192,9 @@ function spec(b) {
}); });
}); });
}); });
}; };
BlockDb.prototype.getBlocksByDate = function(start_ts, end_ts, cb) { BlockDb.prototype.getBlocksByDate = function(start_ts, end_ts, cb) {
var list = []; var list = [];
db.createReadStream({ db.createReadStream({
start: TIMESTAMP_PREFIX + start_ts, start: TIMESTAMP_PREFIX + start_ts,
@ -221,14 +214,10 @@ function spec(b) {
.on('end', function () { .on('end', function () {
return cb(null, list.reverse()); return cb(null, list.reverse());
}); });
}; };
BlockDb.prototype.blockIndex = function(height, cb) { BlockDb.prototype.blockIndex = function(height, cb) {
return Rpc.blockIndex(height,cb); return Rpc.blockIndex(height,cb);
}; };
return BlockDb;
}
module.defineClass(spec);
module.exports = require('soop')(BlockDb);

View File

@ -1,18 +1,13 @@
'use strict'; 'use strict';
var Block = require('bitcore/Block'),
require('classtool');
function spec() {
var Block = require('bitcore/Block').class(),
networks = require('bitcore/networks'), networks = require('bitcore/networks'),
Parser = require('bitcore/util/BinaryParser').class(), Parser = require('bitcore/util/BinaryParser'),
fs = require('fs'), fs = require('fs'),
Buffer = require('buffer').Buffer, Buffer = require('buffer').Buffer,
glob = require('glob'), glob = require('glob'),
async = require('async'); async = require('async');
function BlockExtractor(dataDir, network) { function BlockExtractor(dataDir, network) {
var self = this; var self = this;
var path = dataDir + '/blocks/blk*.dat'; var path = dataDir + '/blocks/blk*.dat';
@ -30,16 +25,16 @@ function spec() {
self.currentParser = null; self.currentParser = null;
self.network = network === 'testnet' ? networks.testnet: networks.livenet; self.network = network === 'testnet' ? networks.testnet: networks.livenet;
self.magic = self.network.magic.toString('hex'); self.magic = self.network.magic.toString('hex');
} }
BlockExtractor.prototype.currentFile = function() { BlockExtractor.prototype.currentFile = function() {
var self = this; var self = this;
return self.files[self.currentFileIndex]; return self.files[self.currentFileIndex];
}; };
BlockExtractor.prototype.nextFile = function() { BlockExtractor.prototype.nextFile = function() {
var self = this; var self = this;
if (self.currentFileIndex < 0) return false; if (self.currentFileIndex < 0) return false;
@ -58,9 +53,9 @@ function spec() {
ret = false; ret = false;
} }
return ret; return ret;
}; };
BlockExtractor.prototype.readCurrentFileSync = function() { BlockExtractor.prototype.readCurrentFileSync = function() {
var self = this; var self = this;
if (self.currentFileIndex < 0 || self.isCurrentRead) return; if (self.currentFileIndex < 0 || self.isCurrentRead) return;
@ -87,11 +82,11 @@ function spec() {
self.currentBuffer = buffer; self.currentBuffer = buffer;
self.currentParser = new Parser(buffer); self.currentParser = new Parser(buffer);
}; };
BlockExtractor.prototype.getNextBlock = function(cb) { BlockExtractor.prototype.getNextBlock = function(cb) {
var self = this; var self = this;
var b; var b;
@ -154,9 +149,7 @@ function spec() {
], function(err) { ], function(err) {
return cb(err,b); return cb(err,b);
}); });
}; };
return BlockExtractor; module.exports = require('soop')(BlockExtractor);
}
module.defineClass(spec);

View File

@ -1,30 +1,26 @@
'use strict'; 'use strict';
require('classtool'); var imports = require('soop').imports();
var util = require('util');
var assert = require('assert');
var async = require('async');
var RpcClient = require('bitcore/RpcClient');
var Script = require('bitcore/Script');
var networks = require('bitcore/networks');
var config = imports.config || require('../config/config');
var Sync = require('./Sync');
var sockets = require('../app/controllers/socket.js');
var BlockExtractor = require('./BlockExtractor.js');
var buffertools = require('buffertools');
// var bitcoreUtil = require('bitcore/util/util');
// var Deserialize = require('bitcore/Deserialize');
var BAD_GEN_ERROR = 'Bad genesis block. Network mismatch between Insight and bitcoind? Insight is configured for:';
function spec() { var BAD_GEN_ERROR_DB = 'Bad genesis block. Network mismatch between Insight and levelDB? Insight is configured for:';
var util = require('util'); function HistoricSync(opts) {
var assert = require('assert');
var RpcClient = require('bitcore/RpcClient').class();
var Script = require('bitcore/Script').class();
var networks = require('bitcore/networks');
var async = require('async');
var config = require('../config/config');
var Sync = require('./Sync').class();
var sockets = require('../app/controllers/socket.js');
var BlockExtractor = require('./BlockExtractor.js').class();
var buffertools = require('buffertools');
// var bitcoreUtil = require('bitcore/util/util');
// var Deserialize = require('bitcore/Deserialize');
var BAD_GEN_ERROR = 'Bad genesis block. Network mismatch between Insight and bitcoind? Insight is configured for:';
var BAD_GEN_ERROR_DB = 'Bad genesis block. Network mismatch between Insight and levelDB? Insight is configured for:';
function HistoricSync(opts) {
opts = opts || {}; opts = opts || {};
this.network = config.network === 'testnet' ? networks.testnet: networks.livenet; this.network = config.network === 'testnet' ? networks.testnet: networks.livenet;
@ -37,18 +33,18 @@ function spec() {
this.rpc = new RpcClient(config.bitcoind); this.rpc = new RpcClient(config.bitcoind);
this.shouldBroadcast = opts.shouldBroadcastSync; this.shouldBroadcast = opts.shouldBroadcastSync;
this.sync = new Sync(opts); this.sync = new Sync(opts);
} }
function p() { function p() {
var args = []; var args = [];
Array.prototype.push.apply(args, arguments); Array.prototype.push.apply(args, arguments);
args.unshift('[historic_sync]'); args.unshift('[historic_sync]');
/*jshint validthis:true */ /*jshint validthis:true */
console.log.apply(this, args); console.log.apply(this, args);
} }
HistoricSync.prototype.showProgress = function() { HistoricSync.prototype.showProgress = function() {
var self = this; var self = this;
if ( self.status ==='syncing' && if ( self.status ==='syncing' &&
@ -65,28 +61,28 @@ function spec() {
sockets.broadcastSyncInfo(self.info()); sockets.broadcastSyncInfo(self.info());
} }
// if (self.syncPercentage > 10) { // if (self.syncPercentage > 10) {
// process.exit(-1); // process.exit(-1);
// } // }
}; };
HistoricSync.prototype.setError = function(err) { HistoricSync.prototype.setError = function(err) {
var self = this; var self = this;
self.error = err.message?err.message:err.toString(); self.error = err.message?err.message:err.toString();
self.status='error'; self.status='error';
self.showProgress(); self.showProgress();
return err; return err;
}; };
HistoricSync.prototype.close = function() { HistoricSync.prototype.close = function() {
this.sync.close(); this.sync.close();
}; };
HistoricSync.prototype.info = function() { HistoricSync.prototype.info = function() {
this.updatePercentage(); this.updatePercentage();
return { return {
status: this.status, status: this.status,
@ -99,15 +95,15 @@ function spec() {
startTs: this.startTs, startTs: this.startTs,
endTs: this.endTs, endTs: this.endTs,
}; };
}; };
HistoricSync.prototype.updatePercentage = function() { HistoricSync.prototype.updatePercentage = function() {
var r = this.syncedBlocks / this.blockChainHeight; var r = this.syncedBlocks / this.blockChainHeight;
this.syncPercentage = parseFloat(100 * r).toFixed(3); this.syncPercentage = parseFloat(100 * r).toFixed(3);
if (this.syncPercentage > 100) this.syncPercentage = 100; if (this.syncPercentage > 100) this.syncPercentage = 100;
}; };
HistoricSync.prototype.getBlockFromRPC = function(cb) { HistoricSync.prototype.getBlockFromRPC = function(cb) {
var self = this; var self = this;
if (!self.currentRpcHash) return cb(); if (!self.currentRpcHash) return cb();
@ -129,9 +125,9 @@ function spec() {
} }
return cb(null, blockInfo); return cb(null, blockInfo);
}); });
}; };
HistoricSync.prototype.getBlockFromFile = function(cb) { HistoricSync.prototype.getBlockFromFile = function(cb) {
var self = this; var self = this;
var blockInfo; var blockInfo;
@ -170,29 +166,29 @@ function spec() {
return cb(err,blockInfo); return cb(err,blockInfo);
}); });
}); });
}; };
HistoricSync.prototype.updateConnectedCountDB = function(cb) { HistoricSync.prototype.updateConnectedCountDB = function(cb) {
var self = this; var self = this;
self.sync.bDb.countConnected(function(err, count) { self.sync.bDb.countConnected(function(err, count) {
self.connectedCountDB = count || 0; self.connectedCountDB = count || 0;
self.syncedBlocks = count || 0; self.syncedBlocks = count || 0;
return cb(err); return cb(err);
}); });
}; };
HistoricSync.prototype.updateBlockChainHeight = function(cb) { HistoricSync.prototype.updateBlockChainHeight = function(cb) {
var self = this; var self = this;
self.rpc.getBlockCount(function(err, res) { self.rpc.getBlockCount(function(err, res) {
self.blockChainHeight = res.result; self.blockChainHeight = res.result;
return cb(err); return cb(err);
}); });
}; };
HistoricSync.prototype.checkNetworkSettings = function(next) { HistoricSync.prototype.checkNetworkSettings = function(next) {
var self = this; var self = this;
self.hasGenesis = false; self.hasGenesis = false;
@ -211,9 +207,9 @@ function spec() {
return next(err); return next(err);
}); });
}); });
}; };
HistoricSync.prototype.updateStartBlock = function(next) { HistoricSync.prototype.updateStartBlock = function(next) {
var self = this; var self = this;
self.startBlock = self.genesis; self.startBlock = self.genesis;
@ -238,39 +234,29 @@ function spec() {
function(err) { function(err) {
if (err) return next(err); if (err) return next(err);
var ret = false; var ret = false;
if ( self.blockChainHeight === blockInfo.height || // Still the tip if ( self.blockChainHeight === blockInfo.height ||
blockInfo.confirmations > 0) { // Or is confirmed blockInfo.confirmations > 0) {
ret = false; ret = false;
} }
else { else {
oldtip = tip; oldtip = tip;
tip = blockInfo.previousblockhash; tip = blockInfo.previousblockhash;
p('Previous TIP is now orphan.'); assert(tip);
if (tip) { p('Previous TIP is now orphan. Back to:' + tip);
p('\tGoing back to:' + tip);
ret = true; ret = true;
} }
else {
p('\tNo able to recover last tip. A Total resync is needed.');
tip = self.genesis;
self.needResync = 1;
ret = false;
}
}
return ret; return ret;
}, },
function(err) { function(err) {
self.startBlock = tip; self.startBlock = tip;
if (!self.needResync) {
p('Resuming sync from block:'+tip); p('Resuming sync from block:'+tip);
}
return next(err); return next(err);
} }
); );
}); });
}; };
HistoricSync.prototype.prepareFileSync = function(opts, next) { HistoricSync.prototype.prepareFileSync = function(opts, next) {
var self = this; var self = this;
if ( opts.forceRPC || !config.bitcoind.dataDir || if ( opts.forceRPC || !config.bitcoind.dataDir ||
@ -309,10 +295,10 @@ function spec() {
}); });
}, next); }, next);
}); });
}; };
//NOP //NOP
HistoricSync.prototype.prepareRpcSync = function(opts, next) { HistoricSync.prototype.prepareRpcSync = function(opts, next) {
var self = this; var self = this;
if (self.blockExtractor) return next(); if (self.blockExtractor) return next();
@ -320,9 +306,9 @@ function spec() {
self.currentRpcHash = self.startBlock; self.currentRpcHash = self.startBlock;
self.allowReorgs = false; self.allowReorgs = false;
return next(); return next();
}; };
HistoricSync.prototype.showSyncStartMessage = function() { HistoricSync.prototype.showSyncStartMessage = function() {
var self = this; var self = this;
p('Got ' + self.connectedCountDB + p('Got ' + self.connectedCountDB +
@ -338,10 +324,10 @@ function spec() {
p('Starting from: ', self.startBlock); p('Starting from: ', self.startBlock);
self.showProgress(); self.showProgress();
}; };
HistoricSync.prototype.setupSyncStatus = function() { HistoricSync.prototype.setupSyncStatus = function() {
var self = this; var self = this;
var step = parseInt( (self.blockChainHeight - self.syncedBlocks) / 1000); var step = parseInt( (self.blockChainHeight - self.syncedBlocks) / 1000);
@ -354,9 +340,9 @@ function spec() {
self.endTs = null; self.endTs = null;
this.error = null; this.error = null;
this.syncPercentage = 0; this.syncPercentage = 0;
}; };
HistoricSync.prototype.prepareToSync = function(opts, next) { HistoricSync.prototype.prepareToSync = function(opts, next) {
var self = this; var self = this;
self.status = 'starting'; self.status = 'starting';
@ -364,22 +350,15 @@ function spec() {
function(s_c) { function(s_c) {
self.checkNetworkSettings(s_c); self.checkNetworkSettings(s_c);
}, },
function(s_c) {
self.updateConnectedCountDB(s_c);
},
function(s_c) { function(s_c) {
self.updateBlockChainHeight(s_c); self.updateBlockChainHeight(s_c);
}, },
function(s_c) { function(s_c) {
self.updateStartBlock(s_c); self.updateStartBlock(s_c);
}, },
function(s_c) {
if (self.needResync) {
self.needResync=0;
self.sync.destroy(s_c);
}
else s_c();
},
function(s_c) {
self.updateConnectedCountDB(s_c);
},
function(s_c) { function(s_c) {
self.prepareFileSync(opts, s_c); self.prepareFileSync(opts, s_c);
}, },
@ -394,10 +373,10 @@ function spec() {
self.setupSyncStatus(); self.setupSyncStatus();
return next(); return next();
}); });
}; };
HistoricSync.prototype.start = function(opts, next) { HistoricSync.prototype.start = function(opts, next) {
var self = this; var self = this;
if (self.status==='starting' || self.status==='syncing') { if (self.status==='starting' || self.status==='syncing') {
@ -439,8 +418,6 @@ function spec() {
}); });
}, next); }, next);
}); });
}; };
return HistoricSync;
}
module.defineClass(spec);
module.exports = require('soop')(HistoricSync);

View File

@ -1,51 +1,48 @@
'use strict'; 'use strict';
require('classtool'); var fs = require('fs');
var bitcoreUtil = require('bitcore/util/util');
var Sync = require('./Sync');
var Peer = require('bitcore/Peer');
var config = require('../config/config');
var networks = require('bitcore/networks');
function spec() { var peerdb_fn = 'peerdb.json';
var fs = require('fs');
var bitcoreUtil = require('bitcore/util/util');
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'; function PeerSync(opts) {
function PeerSync(opts) {
this.connected = false; this.connected = false;
this.peerdb = undefined; this.peerdb = undefined;
this.allowReorgs = false; this.allowReorgs = false;
this.PeerManager = require('bitcore/PeerManager').createClass({ this.PeerManager = require('soop').load('../node_modules/bitcore/PeerManager',{
network: (config.network === 'testnet' ? networks.testnet : networks.livenet) network: (config.network === 'testnet' ? networks.testnet : networks.livenet)
}); });
this.peerman = new this.PeerManager(); this.peerman = new this.PeerManager();
this.load_peers(); this.load_peers();
this.sync = new Sync(opts); this.sync = new Sync(opts);
} }
PeerSync.prototype.load_peers = function() { PeerSync.prototype.load_peers = function() {
this.peerdb = [{ this.peerdb = [{
ipv4: config.bitcoind.host, ipv4: config.bitcoind.host,
port: config.bitcoind.p2pPort port: config.bitcoind.p2pPort
}]; }];
fs.writeFileSync(peerdb_fn, JSON.stringify(this.peerdb)); fs.writeFileSync(peerdb_fn, JSON.stringify(this.peerdb));
}; };
PeerSync.prototype.info = function() { PeerSync.prototype.info = function() {
return { return {
connected: this.connected, connected: this.connected,
host: this.peerdb[0].ipv4, host: this.peerdb[0].ipv4,
port: this.peerdb[0].port port: this.peerdb[0].port
}; };
}; };
PeerSync.prototype.handleInv = function(info) { PeerSync.prototype.handleInv = function(info) {
var invs = info.message.invs; var invs = info.message.invs;
info.conn.sendGetData(invs); info.conn.sendGetData(invs);
}; };
PeerSync.prototype.handleTx = function(info) { PeerSync.prototype.handleTx = function(info) {
var tx = info.message.tx.getStandardizedObject(); var tx = info.message.tx.getStandardizedObject();
tx.outs = info.message.tx.outs; tx.outs = info.message.tx.outs;
tx.ins = info.message.tx.ins; tx.ins = info.message.tx.ins;
@ -57,9 +54,9 @@ function spec() {
console.log('[p2p_sync] Error in handle TX: ' + JSON.stringify(err)); console.log('[p2p_sync] Error in handle TX: ' + JSON.stringify(err));
} }
}); });
}; };
PeerSync.prototype.handleBlock = function(info) { PeerSync.prototype.handleBlock = function(info) {
var self = this; var self = this;
var block = info.message.block; var block = info.message.block;
var blockHash = bitcoreUtil.formatHashFull(block.calcHash()); var blockHash = bitcoreUtil.formatHashFull(block.calcHash());
@ -85,15 +82,15 @@ function spec() {
console.log('[p2p_sync] Error in handle Block: ' + err); console.log('[p2p_sync] Error in handle Block: ' + err);
} }
}); });
}; };
PeerSync.prototype.handle_connected = function(data) { PeerSync.prototype.handle_connected = function(data) {
var peerman = data.pm; var peerman = data.pm;
var peers_n = peerman.peers.length; var peers_n = peerman.peers.length;
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() { PeerSync.prototype.run = function() {
var self = this; var self = this;
this.peerdb.forEach(function(datum) { this.peerdb.forEach(function(datum) {
@ -114,14 +111,11 @@ function spec() {
}); });
this.peerman.start(); this.peerman.start();
}; };
PeerSync.prototype.close = function() { PeerSync.prototype.close = function() {
this.sync.close(); this.sync.close();
}; };
return PeerSync; module.exports = require('soop')(PeerSync);
}
module.defineClass(spec);

View File

@ -1,14 +1,11 @@
'use strict'; 'use strict';
require('classtool'); var imports = require('soop').imports();
var fs = require('fs');
var buffertools = require('buffertools');
var db = imports.db || JSON.parse( fs.readFileSync(imports.poolMatchFile || './poolMatchFile.json'));
function spec(b) { var PoolMatch = function() {
var fs = require('fs');
var buffertools = require('buffertools');
var db = b.db || JSON.parse( fs.readFileSync(b.poolMatchFile || './poolMatchFile.json'));
var PoolMatch = function() {
var self = this; var self = this;
self.strings = {}; self.strings = {};
@ -20,19 +17,16 @@ function spec(b) {
}; };
}); });
}); });
}; };
PoolMatch.prototype.match = function(buffer) { PoolMatch.prototype.match = function(buffer) {
var self = this; var self = this;
for(var k in self.strings) { for(var k in self.strings) {
if (buffertools.indexOf(buffer, k) >= 0) { if (buffertools.indexOf(buffer, k) >= 0) {
return self.strings[k]; return self.strings[k];
} }
} }
}; };
return PoolMatch;
}
module.defineClass(spec);
module.exports = require('soop')(PoolMatch);

View File

@ -1,21 +1,19 @@
'use strict'; 'use strict';
require('classtool'); var imports = require('soop').imports();
var RpcClient = require('bitcore/RpcClient'),
function spec(b) { BitcoreBlock = require('bitcore/Block'),
var RpcClient = require('bitcore/RpcClient').class(),
BitcoreBlock = require('bitcore/Block').class(),
bitcoreUtil = require('bitcore/util/util'), bitcoreUtil = require('bitcore/util/util'),
util = require('util'), util = require('util'),
config = require('../config/config'); config = require('../config/config');
var bitcoreRpc = b.bitcoreRpc || new RpcClient(config.bitcoind); var bitcoreRpc = imports.bitcoreRpc || new RpcClient(config.bitcoind);
function Rpc() { function Rpc() {
} }
Rpc._parseTxResult = function(info) { Rpc._parseTxResult = function(info) {
var b = new Buffer(info.hex,'hex'); var b = new Buffer(info.hex,'hex');
// remove fields we dont need, to speed and adapt the information // remove fields we dont need, to speed and adapt the information
@ -39,10 +37,10 @@ function spec(b) {
info.size = b.length; info.size = b.length;
return info; return info;
}; };
Rpc.errMsg = function(err) { Rpc.errMsg = function(err) {
var e = err; var e = err;
e.message += util.format(' [Host: %s:%d User:%s Using password:%s]', e.message += util.format(' [Host: %s:%d User:%s Using password:%s]',
bitcoreRpc.host, bitcoreRpc.host,
@ -51,9 +49,9 @@ function spec(b) {
bitcoreRpc.pass?'yes':'no' bitcoreRpc.pass?'yes':'no'
); );
return e; return e;
}; };
Rpc.getTxInfo = function(txid, doNotParse, cb) { Rpc.getTxInfo = function(txid, doNotParse, cb) {
var self = this; var self = this;
if (typeof doNotParse === 'function') { if (typeof doNotParse === 'function') {
@ -69,19 +67,19 @@ function spec(b) {
var info = doNotParse ? txInfo.result : self._parseTxResult(txInfo.result); var info = doNotParse ? txInfo.result : self._parseTxResult(txInfo.result);
return cb(null,info); return cb(null,info);
}); });
}; };
Rpc.blockIndex = function(height, cb) { Rpc.blockIndex = function(height, cb) {
var self = this; var self = this;
bitcoreRpc.getBlockHash(height, function(err, bh){ bitcoreRpc.getBlockHash(height, function(err, bh){
if (err) return cb(self.errMsg(err)); if (err) return cb(self.errMsg(err));
cb(null, { blockHash: bh.result }); cb(null, { blockHash: bh.result });
}); });
}; };
Rpc.getBlock = function(hash, cb) { Rpc.getBlock = function(hash, cb) {
var self = this; var self = this;
bitcoreRpc.getBlock(hash, function(err,info) { bitcoreRpc.getBlock(hash, function(err,info) {
@ -95,9 +93,9 @@ function spec(b) {
return cb(err,info.result); return cb(err,info.result);
}); });
}; };
Rpc.sendRawTransaction = function(rawtx, cb) { Rpc.sendRawTransaction = function(rawtx, cb) {
var self = this; var self = this;
bitcoreRpc.sendRawTransaction(rawtx, function(err, txid) { bitcoreRpc.sendRawTransaction(rawtx, function(err, txid) {
if (err && err.code === -5) return cb(err); // transaction already in block chain if (err && err.code === -5) return cb(err); // transaction already in block chain
@ -105,10 +103,8 @@ function spec(b) {
return cb(err, txid.result); return cb(err, txid.result);
}); });
}; };
return Rpc; module.exports = require('soop')(Rpc);
}
module.defineClass(spec);

View File

@ -1,37 +1,32 @@
'use strict'; 'use strict';
require('classtool'); var imports = require('soop').imports();
var sockets = require('../app/controllers/socket.js');
var config = imports.config || require('../config/config');
var networks = require('bitcore/networks');
var async = require('async');
function spec() { function Sync(opts) {
var sockets = require('../app/controllers/socket.js');
var BlockDb = require('./BlockDb').class();
var TransactionDb = require('./TransactionDb').class();
var config = require('../config/config');
var networks = require('bitcore/networks');
var async = require('async');
function Sync(opts) {
this.opts = opts || {}; this.opts = opts || {};
this.bDb = new BlockDb(opts); this.bDb = require('./BlockDb').default();
this.txDb = new TransactionDb(opts); this.txDb = require('./TransactionDb').default();
this.txDb.on('tx_for_address', this.handleTxForAddress.bind(this)); this.txDb.on('tx_for_address', this.handleTxForAddress.bind(this));
this.txDb.on('new_tx', this.handleNewTx.bind(this)); this.txDb.on('new_tx', this.handleNewTx.bind(this));
this.bDb.on('new_block', this.handleNewBlock.bind(this)); this.bDb.on('new_block', this.handleNewBlock.bind(this));
this.network = config.network === 'testnet' ? networks.testnet : networks.livenet; this.network = config.network === 'testnet' ? networks.testnet : networks.livenet;
} }
Sync.prototype.close = function(cb) { Sync.prototype.close = function(cb) {
var self = this; var self = this;
self.txDb.close(function() { self.txDb.close(function() {
self.bDb.close(cb); self.bDb.close(cb);
}); });
}; };
Sync.prototype.destroy = function(next) { Sync.prototype.destroy = function(next) {
var self = this; var self = this;
async.series([ async.series([
@ -42,9 +37,9 @@ function spec() {
self.txDb.drop(b); self.txDb.drop(b);
}, },
], next); ], next);
}; };
/* /*
* Arrives a NEW block, which is the new TIP * Arrives a NEW block, which is the new TIP
* *
* Case 0) Simple case * Case 0) Simple case
@ -74,7 +69,7 @@ function spec() {
* *
*/ */
Sync.prototype.storeTipBlock = function(b, allowReorgs, cb) { Sync.prototype.storeTipBlock = function(b, allowReorgs, cb) {
if (typeof allowReorgs === 'function') { if (typeof allowReorgs === 'function') {
cb = allowReorgs; cb = allowReorgs;
@ -151,11 +146,11 @@ function spec() {
} }
return cb(err); return cb(err);
}); });
}; };
Sync.prototype.processReorg = function(oldTip, oldNext, newPrev, cb) { Sync.prototype.processReorg = function(oldTip, oldNext, newPrev, cb) {
var self = this; var self = this;
var orphanizeFrom; var orphanizeFrom;
@ -196,17 +191,17 @@ function spec() {
function(err) { function(err) {
return cb(err); return cb(err);
}); });
}; };
Sync.prototype.setBlockMain = function(hash, isMain, cb) { Sync.prototype.setBlockMain = function(hash, isMain, cb) {
var self = this; var self = this;
self.bDb.setMain(hash, isMain, function(err) { self.bDb.setMain(hash, isMain, function(err) {
if (err) return cb(err); if (err) return cb(err);
return self.txDb.handleBlockChange(hash, isMain, cb); return self.txDb.handleBlockChange(hash, isMain, cb);
}); });
}; };
Sync.prototype.setBranchOrphan = function(fromHash, cb) { Sync.prototype.setBranchOrphan = function(fromHash, cb) {
var self = this, var self = this,
hashInterator = fromHash; hashInterator = fromHash;
@ -223,9 +218,9 @@ function spec() {
}); });
}); });
}, cb); }, cb);
}; };
Sync.prototype.setBranchConnectedBackwards = function(fromHash, cb) { Sync.prototype.setBranchConnectedBackwards = function(fromHash, cb) {
var self = this, var self = this,
hashInterator = fromHash, hashInterator = fromHash,
lastHash = fromHash, lastHash = fromHash,
@ -254,36 +249,34 @@ function spec() {
return cb(err, hashInterator, lastHash); return cb(err, hashInterator, lastHash);
} }
); );
}; };
Sync.prototype.handleTxForAddress = function(data) { Sync.prototype.handleTxForAddress = function(data) {
if (this.opts.shouldBroadcast) { if (this.opts.shouldBroadcast) {
sockets.broadcastAddressTx(data.address, data.txid); sockets.broadcastAddressTx(data.address, data.txid);
} }
}; };
Sync.prototype.handleNewTx = function(data) { Sync.prototype.handleNewTx = function(data) {
if (this.opts.shouldBroadcast) { if (this.opts.shouldBroadcast) {
sockets.broadcastTx(data.tx); sockets.broadcastTx(data.tx);
} }
}; };
Sync.prototype.handleNewBlock = function(data) { Sync.prototype.handleNewBlock = function(data) {
if (this.opts.shouldBroadcast) { if (this.opts.shouldBroadcast) {
sockets.broadcastBlock(data.blockid); sockets.broadcastBlock(data.blockid);
} }
}; };
Sync.prototype.storeTxs = function(txs, cb) { Sync.prototype.storeTxs = function(txs, cb) {
var self = this; var self = this;
self.txDb.createFromArray(txs, null, function(err) { self.txDb.createFromArray(txs, null, function(err) {
if (err) return cb(err); if (err) return cb(err);
return cb(err); return cb(err);
}); });
}; };
return Sync; module.exports = require('soop')(Sync);
}
module.defineClass(spec);

View File

@ -1,66 +1,63 @@
'use strict'; 'use strict';
require('classtool'); var imports = require('soop').imports();
var ThisParent = imports.parent || require('events').EventEmitter;
// blockHash -> txid mapping
var IN_BLK_PREFIX = 'txb-'; //txb-<txid>-<block> => 1/0 (connected or not)
function spec(b) { // Only for orphan blocks
var FROM_BLK_PREFIX = 'tx-'; //tx-<block>-<txid> => 1
var superclass = b.superclass || require('events').EventEmitter; // to show tx outs
// blockHash -> txid mapping var OUTS_PREFIX = 'txo-'; //txo-<txid>-<n> => [addr, btc_sat]
var IN_BLK_PREFIX = 'txb-'; //txb-<txid>-<block> => 1/0 (connected or not) var SPENT_PREFIX = 'txs-'; //txs-<txid(out)>-<n(out)>-<txid(in)>-<n(in)> = ts
// Only for orphan blocks // to sum up addr balance (only outs, spents are gotten later)
var FROM_BLK_PREFIX = 'tx-'; //tx-<block>-<txid> => 1 var ADDR_PREFIX = 'txa-'; //txa-<addr>-<txid>-<n> => + btc_sat:ts
// to show tx outs // TODO: use bitcore networks module
var OUTS_PREFIX = 'txo-'; //txo-<txid>-<n> => [addr, btc_sat] var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b';
var SPENT_PREFIX = 'txs-'; //txs-<txid(out)>-<n(out)>-<txid(in)>-<n(in)> = ts var CONCURRENCY = 10;
// to sum up addr balance (only outs, spents are gotten later) var MAX_OPEN_FILES = 500;
var ADDR_PREFIX = 'txa-'; //txa-<addr>-<txid>-<n> => + btc_sat:ts
// TODO: use bitcore networks module
var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b';
var CONCURRENCY = 10;
var MAX_OPEN_FILES = 500;
// var CONFIRMATION_NR_TO_NOT_CHECK = 10; //Spend // var CONFIRMATION_NR_TO_NOT_CHECK = 10; //Spend
/** /**
* Module dependencies. * Module dependencies.
*/ */
var Rpc = b.rpc || require('./Rpc').class(), var Rpc = imports.rpc || require('./Rpc'),
util = require('bitcore/util/util'), util = require('bitcore/util/util'),
levelup = require('levelup'), levelup = require('levelup'),
async = require('async'), async = require('async'),
config = require('../config/config'), config = require('../config/config'),
assert = require('assert'); assert = require('assert');
var db = b.db || levelup(config.leveldb + '/txs',{maxOpenFiles: MAX_OPEN_FILES} ); var db = imports.db || levelup(config.leveldb + '/txs',{maxOpenFiles: MAX_OPEN_FILES} );
var Script = require('bitcore/Script').class(); var Script = require('bitcore/Script');
// This is 0.1.2 => c++ version of base57-native // This is 0.1.2 = > c++ version of base57-native
var base58 = require('base58-native').base58Check; var base58 = require('base58-native').base58Check;
var encodedData = require('bitcore/util/EncodedData').class({ var encodedData = require('soop').load('bitcore/util/EncodedData',{
base58: base58 base58: base58
}); });
var versionedData = require('bitcore/util/VersionedData').class({ var versionedData= require('soop').load('bitcore/util/VersionedData',{
superclass: encodedData parent: encodedData
}); });
var Address = require('bitcore/Address').class({ var Address = require('soop').load('bitcore/Address',{
superclass: versionedData parent: versionedData
}); });
var bitutil = require('bitcore/util/util'); var bitutil = require('bitcore/util/util');
var networks = require('bitcore/networks'); var networks = require('bitcore/networks');
var TransactionDb = function() { var TransactionDb = function() {
TransactionDb.super(this, arguments); TransactionDb.super(this, arguments);
this.network = config.network === 'testnet' ? networks.testnet : networks.livenet; this.network = config.network === 'testnet' ? networks.testnet : networks.livenet;
}; };
TransactionDb.superclass = superclass; TransactionDb.parent = ThisParent;
TransactionDb.prototype.close = function(cb) { TransactionDb.prototype.close = function(cb) {
db.close(cb); db.close(cb);
}; };
TransactionDb.prototype.drop = function(cb) { TransactionDb.prototype.drop = function(cb) {
var path = config.leveldb + '/txs'; var path = config.leveldb + '/txs';
db.close(function() { db.close(function() {
require('leveldown').destroy(path, function() { require('leveldown').destroy(path, function() {
@ -68,10 +65,10 @@ function spec(b) {
return cb(); return cb();
}); });
}); });
}; };
TransactionDb.prototype.has = function(txid, cb) { TransactionDb.prototype.has = function(txid, cb) {
var k = OUTS_PREFIX + txid; var k = OUTS_PREFIX + txid;
db.get(k, function(err, val) { db.get(k, function(err, val) {
@ -87,9 +84,9 @@ function spec(b) {
} }
return cb(err, ret); return cb(err, ret);
}); });
}; };
TransactionDb.prototype._addSpentInfo = function(r, txid, index, ts) { TransactionDb.prototype._addSpentInfo = function(r, txid, index, ts) {
if (r.spentTxId) { if (r.spentTxId) {
if (!r.multipleSpentAttempts) { if (!r.multipleSpentAttempts) {
r.multipleSpentAttempts = [{ r.multipleSpentAttempts = [{
@ -106,11 +103,11 @@ function spec(b) {
r.spentIndex = parseInt(index); r.spentIndex = parseInt(index);
r.spentTs = parseInt(ts); r.spentTs = parseInt(ts);
} }
}; };
// This is not used now // This is not used now
TransactionDb.prototype.fromTxId = function(txid, cb) { TransactionDb.prototype.fromTxId = function(txid, cb) {
var self = this; var self = this;
var k = OUTS_PREFIX + txid; var k = OUTS_PREFIX + txid;
var ret = []; var ret = [];
@ -158,10 +155,10 @@ function spec(b) {
return cb(err, ret); return cb(err, ret);
}); });
}); });
}; };
TransactionDb.prototype._fillSpent = function(info, cb) { TransactionDb.prototype._fillSpent = function(info, cb) {
var self = this; var self = this;
if (!info) return cb(); if (!info) return cb();
@ -181,10 +178,10 @@ function spec(b) {
.on('end', function(err) { .on('end', function(err) {
return cb(err); return cb(err);
}); });
}; };
TransactionDb.prototype._fillOutpoints = function(info, cb) { TransactionDb.prototype._fillOutpoints = function(info, cb) {
var self = this; var self = this;
if (!info || info.isCoinBase) return cb(); if (!info || info.isCoinBase) return cb();
@ -210,9 +207,9 @@ function spec(b) {
valueIn += i.valueSat; valueIn += i.valueSat;
/* /*
* If confirmed by bitcoind, we could not check for double spents * If confirmed by bitcoind, we could not check for double spents
* but we prefer to keep the flag of double spent attempt * but we prefer to keep the flag of double spent attempt
* *
if (info.confirmations if (info.confirmations
&& info.confirmations >= CONFIRMATION_NR_TO_NOT_CHECK) && info.confirmations >= CONFIRMATION_NR_TO_NOT_CHECK)
return c_in(); return c_in();
@ -250,9 +247,9 @@ isspent
} }
return cb(); return cb();
}); });
}; };
TransactionDb.prototype._getInfo = function(txid, next) { TransactionDb.prototype._getInfo = function(txid, next) {
var self = this; var self = this;
Rpc.getTxInfo(txid, function(err, info) { Rpc.getTxInfo(txid, function(err, info) {
@ -264,19 +261,19 @@ isspent
}); });
}); });
}); });
}; };
// Simplified / faster Info version: No spent / outpoints info. // Simplified / faster Info version: No spent / outpoints info.
TransactionDb.prototype.fromIdInfoSimple = function(txid, cb) { TransactionDb.prototype.fromIdInfoSimple = function(txid, cb) {
Rpc.getTxInfo(txid, true, function(err, info) { Rpc.getTxInfo(txid, true, function(err, info) {
if (err) return cb(err); if (err) return cb(err);
if (!info) return cb(); if (!info) return cb();
return cb(err, info); return cb(err, info);
}); });
}; };
TransactionDb.prototype.fromIdWithInfo = function(txid, cb) { TransactionDb.prototype.fromIdWithInfo = function(txid, cb) {
var self = this; var self = this;
self._getInfo(txid, function(err, info) { self._getInfo(txid, function(err, info) {
@ -287,9 +284,9 @@ isspent
info: info info: info
}); });
}); });
}; };
TransactionDb.prototype.fromTxIdN = function(txid, n, confirmations, cb) { TransactionDb.prototype.fromTxIdN = function(txid, n, confirmations, cb) {
var self = this; var self = this;
var k = OUTS_PREFIX + txid + '-' + n; var k = OUTS_PREFIX + txid + '-' + n;
@ -335,9 +332,9 @@ isspent
return cb(null, ret); return cb(null, ret);
}); });
}); });
}; };
TransactionDb.prototype.fillConfirmations = function(o, cb) { TransactionDb.prototype.fillConfirmations = function(o, cb) {
var self = this; var self = this;
self.isConfirmed(o.txid, function(err, is) { self.isConfirmed(o.txid, function(err, is) {
@ -368,9 +365,9 @@ isspent
}); });
} }
}); });
}; };
TransactionDb.prototype.fromAddr = function(addr, cb) { TransactionDb.prototype.fromAddr = function(addr, cb) {
var self = this; var self = this;
var k = ADDR_PREFIX + addr + '-'; var k = ADDR_PREFIX + addr + '-';
@ -420,10 +417,10 @@ isspent
}); });
}); });
}); });
}; };
TransactionDb.prototype.removeFromTxId = function(txid, cb) { TransactionDb.prototype.removeFromTxId = function(txid, cb) {
async.series([ async.series([
@ -453,12 +450,12 @@ isspent
cb(err); cb(err);
}); });
}; };
// TODO. replace with // TODO. replace with
// Script.prototype.getAddrStrs if that one get merged in bitcore // Script.prototype.getAddrStrs if that one get merged in bitcore
TransactionDb.prototype.getAddrStr = function(s) { TransactionDb.prototype.getAddrStr = function(s) {
var self = this; var self = this;
var addrStrs = []; var addrStrs = [];
@ -491,9 +488,9 @@ isspent
} }
return addrStrs; return addrStrs;
}; };
TransactionDb.prototype.adaptTxObject = function(txInfo) { TransactionDb.prototype.adaptTxObject = function(txInfo) {
var self = this; var self = this;
// adapt bitcore TX object to bitcoind JSON response // adapt bitcore TX object to bitcoind JSON response
txInfo.txid = txInfo.hash; txInfo.txid = txInfo.hash;
@ -543,11 +540,11 @@ isspent
} }
return o; return o;
}); });
}; };
TransactionDb.prototype.add = function(tx, blockhash, cb) { TransactionDb.prototype.add = function(tx, blockhash, cb) {
var self = this; var self = this;
var addrs = []; var addrs = [];
@ -631,11 +628,11 @@ isspent
return cb(err); return cb(err);
}); });
}; };
TransactionDb.prototype.setConfirmation = function(txId, blockHash, confirmed, c) { TransactionDb.prototype.setConfirmation = function(txId, blockHash, confirmed, c) {
if (!blockHash) return c(); if (!blockHash) return c();
confirmed = confirmed ? 1 : 0; confirmed = confirmed ? 1 : 0;
@ -644,11 +641,11 @@ isspent
.put(IN_BLK_PREFIX + txId + '-' + blockHash, confirmed) .put(IN_BLK_PREFIX + txId + '-' + blockHash, confirmed)
.put(FROM_BLK_PREFIX + blockHash + '-' + txId, 1) .put(FROM_BLK_PREFIX + blockHash + '-' + txId, 1)
.write(c); .write(c);
}; };
// This slowdown addr balance calculation by 100% // This slowdown addr balance calculation by 100%
TransactionDb.prototype.isConfirmed = function(txId, c) { TransactionDb.prototype.isConfirmed = function(txId, c) {
var k = IN_BLK_PREFIX + txId; var k = IN_BLK_PREFIX + txId;
var ret = false; var ret = false;
@ -665,14 +662,15 @@ isspent
.on('end', function(err) { .on('end', function(err) {
return c(err, ret); return c(err, ret);
}); });
}; };
TransactionDb.prototype.handleBlockChange = function(hash, isMain, cb) { TransactionDb.prototype.handleBlockChange = function(hash, isMain, cb) {
var toChange = []; var toChange = [];
console.log('\tSearching Txs from block:' + hash); console.log('\tSearching Txs from block:' + hash);
var k = FROM_BLK_PREFIX + hash; var k = FROM_BLK_PREFIX + hash;
var k2 = IN_BLK_PREFIX; var k2 = IN_BLK_PREFIX;
// This is slow, but prevent us to create a new block->tx index.
db.createReadStream({ db.createReadStream({
start: k, start: k,
end: k + '~' end: k + '~'
@ -693,10 +691,10 @@ isspent
console.log('\t%s %d Txs', isMain ? 'Confirming' : 'Invalidating', toChange.length); console.log('\t%s %d Txs', isMain ? 'Confirming' : 'Invalidating', toChange.length);
db.batch(toChange, cb); db.batch(toChange, cb);
}); });
}; };
// txs can be a [hashes] or [txObjects] // txs can be a [hashes] or [txObjects]
TransactionDb.prototype.createFromArray = function(txs, blockHash, next) { TransactionDb.prototype.createFromArray = function(txs, blockHash, next) {
var self = this; var self = this;
if (!txs) return next(); if (!txs) return next();
@ -717,16 +715,14 @@ isspent
function(err) { function(err) {
return next(err); return next(err);
}); });
}; };
TransactionDb.prototype.createFromBlock = function(b, next) { TransactionDb.prototype.createFromBlock = function(b, next) {
var self = this; var self = this;
if (!b || !b.tx) return next(); if (!b || !b.tx) return next();
return self.createFromArray(b.tx, b.hash, next); return self.createFromArray(b.tx, b.hash, next);
}; };
return TransactionDb; module.exports = require('soop')(TransactionDb);
}
module.defineClass(spec);

View File

@ -1,7 +1,7 @@
{ {
"name": "insight-bitcore-api", "name": "insight-bitcore-api",
"description": "An open-source bitcoin blockchain API. The Insight API provides you with a convenient, powerful and simple way to query and broadcast data on the bitcoin network and build your own services with it.", "description": "An open-source bitcoin blockchain API. The Insight API provides you with a convenient, powerful and simple way to query and broadcast data on the bitcoin network and build your own services with it.",
"version": "0.1.3", "version": "0.1.4",
"author": { "author": {
"name": "Ryan X Charles", "name": "Ryan X Charles",
"email": "ryan@bitpay.com" "email": "ryan@bitpay.com"
@ -36,13 +36,11 @@
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
"insight", "insight",
"secret", "insight api",
"enigma", "blockchain",
"riddle", "bitcoin api",
"mystification", "blockchain api",
"puzzle", "json",
"conundrum",
"api",
"bitcore" "bitcore"
], ],
"engines": { "engines": {
@ -52,12 +50,13 @@
"start": "node node_modules/grunt-cli/bin/grunt" "start": "node node_modules/grunt-cli/bin/grunt"
}, },
"dependencies": { "dependencies": {
"bitcore": "~0.1.6",
"base58-native": "0.1.2", "base58-native": "0.1.2",
"async": "*", "async": "*",
"leveldown": "*", "leveldown": "*",
"levelup": "*", "levelup": "*",
"glob": "*", "glob": "*",
"classtool": "*", "soop": "git://github.com/gasteve/node-soop.git",
"commander": "*", "commander": "*",
"bignum": "*", "bignum": "*",
"express": "~3.4.7", "express": "~3.4.7",
@ -67,7 +66,6 @@
"moment": "~2.5.0", "moment": "~2.5.0",
"sinon": "~1.7.3", "sinon": "~1.7.3",
"chai": "~1.8.1", "chai": "~1.8.1",
"bitcore": "git://github.com/bitpay/bitcore.git",
"bufferput": "git://github.com/bitpay/node-bufferput.git", "bufferput": "git://github.com/bitpay/node-bufferput.git",
"xmlhttprequest": "~1.6.0" "xmlhttprequest": "~1.6.0"
}, },

View File

@ -8,7 +8,7 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var assert = require('assert'), var assert = require('assert'),
fs = require('fs'), fs = require('fs'),
util = require('util'), util = require('util'),
TransactionDb = require('../../lib/TransactionDb').class(); TransactionDb = require('../../lib/TransactionDb').default();
var txItemsValid = JSON.parse(fs.readFileSync('test/integration/txitems.json')); var txItemsValid = JSON.parse(fs.readFileSync('test/integration/txitems.json'));
var txDb; var txDb;
@ -16,7 +16,7 @@ var txDb;
describe('TransactionDb fromIdWithInfo', function(){ describe('TransactionDb fromIdWithInfo', function(){
before(function(c) { before(function(c) {
txDb = new TransactionDb(); txDb = TransactionDb;
return c(); return c();
}); });
@ -118,7 +118,7 @@ describe('TransactionDb fromIdWithInfo', function(){
describe('TransactionDb Outs', function(){ describe('TransactionDb Outs', function(){
before(function(c) { before(function(c) {
txDb = new TransactionDb(); txDb = TransactionDb;
return c(); return c();
}); });

View File

@ -11,7 +11,7 @@ var
util = require('util'), util = require('util'),
async = require('async'), async = require('async'),
config = require('../../config/config'), config = require('../../config/config'),
TransactionDb = require('../../lib/TransactionDb').class(); TransactionDb = require('../../lib/TransactionDb').default();
var spentValid = JSON.parse(fs.readFileSync('test/integration/spent.json')); var spentValid = JSON.parse(fs.readFileSync('test/integration/spent.json'));
@ -20,7 +20,7 @@ var txDb;
describe('TransactionDb Expenses', function(){ describe('TransactionDb Expenses', function(){
before(function(c) { before(function(c) {
txDb = new TransactionDb(); txDb = TransactionDb;
// lets spend! // lets spend!
async.each(Object.keys(spentValid), async.each(Object.keys(spentValid),

View File

@ -6,8 +6,8 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var assert = require('assert'), var assert = require('assert'),
fs = require('fs'), fs = require('fs'),
Address = require('../../app/models/Address').class(), Address = require('../../app/models/Address'),
TransactionDb = require('../../lib/TransactionDb').class(), TransactionDb = require('../../lib/TransactionDb').default(),
addrValid = JSON.parse(fs.readFileSync('test/integration/addr.json')), addrValid = JSON.parse(fs.readFileSync('test/integration/addr.json')),
utxoValid = JSON.parse(fs.readFileSync('test/integration/utxo.json')); utxoValid = JSON.parse(fs.readFileSync('test/integration/utxo.json'));
@ -15,7 +15,7 @@ var txDb;
describe('Address balances', function() { describe('Address balances', function() {
before(function(c) { before(function(c) {
txDb = new TransactionDb(); txDb = TransactionDb;
return c(); return c();
}); });

View File

@ -10,14 +10,14 @@ var TESTING_BLOCK = '000000000185678d3d7ecc9962c96418174431f93fe20bf216d55652724
var var
assert = require('assert'), assert = require('assert'),
// config = require('../../config/config'), // config = require('../../config/config'),
BlockDb = require('../../lib/BlockDb').class(); BlockDb = require('../../lib/BlockDb').default();
var bDb; var bDb;
describe('BlockDb fromHashWithInfo', function() { describe('BlockDb fromHashWithInfo', function() {
before(function(c) { before(function(c) {
bDb = new BlockDb(); bDb = BlockDb;
return c(); return c();
}); });

View File

@ -7,7 +7,7 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var assert = require('assert'), var assert = require('assert'),
config = require('../../config/config'), config = require('../../config/config'),
BlockExtractor = require('../../lib/BlockExtractor').class(), BlockExtractor = require('../../lib/BlockExtractor'),
networks = require('bitcore/networks'), networks = require('bitcore/networks'),
util = require('bitcore/util/util'); util = require('bitcore/util/util');

View File

@ -9,7 +9,7 @@ var START_TS = 1;
var END_TS = '1296688928~'; // 2/2/2011 23:23PM var END_TS = '1296688928~'; // 2/2/2011 23:23PM
var assert = require('assert'), var assert = require('assert'),
BlockDb = require('../../lib/BlockDb').class(); BlockDb = require('../../lib/BlockDb').default();
var bDb; var bDb;
@ -17,7 +17,7 @@ describe('BlockDb getBlocksByDate', function(){
before(function(c) { before(function(c) {
bDb = new BlockDb(); bDb = BlockDb;
return c(); return c();
}); });

View File

@ -1,8 +1,8 @@
'use strict'; 'use strict';
var BlockDb = require('../../lib/BlockDb').class(); var BlockDb = require('../../lib/BlockDb').default();
var height_needed = 180000; var height_needed = 180000;
var bDb = new BlockDb(); var bDb = BlockDb;
var expect = require('chai').expect; var expect = require('chai').expect;

View File

@ -4,7 +4,7 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var assert = require('assert'), var assert = require('assert'),
Status = require('../../app/models/Status').class(); Status = require('../../app/models/Status');
describe('Status', function(){ describe('Status', function(){

View File

@ -3,7 +3,7 @@ var chai = require('chai'),
expect = chai.expect, expect = chai.expect,
sinon = require('sinon'); sinon = require('sinon');
var PeerSync = require('../../lib/PeerSync.js').class(); var PeerSync = require('../../lib/PeerSync.js');
describe('PeerSync', function() { describe('PeerSync', function() {
var ps; var ps;

View File

@ -3,7 +3,7 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var PeerSync = require('../lib/PeerSync').class(); var PeerSync = require('../lib/PeerSync');
var PROGRAM_VERSION = '0.1'; var PROGRAM_VERSION = '0.1';
var program = require('commander'); var program = require('commander');

View File

@ -7,7 +7,7 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var SYNC_VERSION = '0.1'; var SYNC_VERSION = '0.1';
var program = require('commander'); var program = require('commander');
var HistoricSync = require('../lib/HistoricSync').class(); var HistoricSync = require('../lib/HistoricSync');
var async = require('async'); var async = require('async');
program program