From 5ddddb520d675a19ac3e1c228d2044a403f4f3a3 Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Wed, 15 Jan 2014 17:15:14 -0300 Subject: [PATCH 01/10] Status API: getInfo --- app/models/Status.js | 35 +++++++++++++++++++++++++++++++++++ test/model/status.js | 34 ++++++++++++++++++++++++++++++++++ util/status_info.js | 20 ++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 app/models/Status.js create mode 100644 test/model/status.js create mode 100755 util/status_info.js diff --git a/app/models/Status.js b/app/models/Status.js new file mode 100644 index 00000000..283032b5 --- /dev/null +++ b/app/models/Status.js @@ -0,0 +1,35 @@ +'use strict'; + +require('classtool'); + +function spec() { + var async = require('async'); + var RpcClient = require('bitcore/RpcClient').class(); + var config = require('../../config/config'); + var rpc = new RpcClient(config.bitcoind); + + function Status() { + this.info = {}; + } + + Status.prototype.getInfo = function(next) { + var that = this; + async.series([ + function (cb) { + rpc.getInfo(function(err, block){ + if (err) return cb(err); + + that.info = block.result; + return cb(); + }); + } + ], function (err) { + return next(err); + }); + }; + + return Status; + +} +module.defineClass(spec); + diff --git a/test/model/status.js b/test/model/status.js new file mode 100644 index 00000000..0bcd6cdc --- /dev/null +++ b/test/model/status.js @@ -0,0 +1,34 @@ +#!/usr/bin/env node + +process.env.NODE_ENV = process.env.NODE_ENV || 'development'; + +var + assert = require('assert'), + config = require('../../config/config'), + Status = require('../../app/models/Status').class(), + mongoose= require('mongoose'); + +describe('Status', function(){ + + before(function(done) { + mongoose.connect(config.db); + done(); + }); + + after(function(done) { + mongoose.connection.close(); + done(); + }); + + it('getInfo', function(done) { + var d = new Status(); + + d.getInfo(function(err) { + if (err) done(err); + assert.equal(4096, d.info.difficulty); + done(); + }); + }); + +}); + diff --git a/util/status_info.js b/util/status_info.js new file mode 100755 index 00000000..1b4deb80 --- /dev/null +++ b/util/status_info.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node +process.env.NODE_ENV = process.env.NODE_ENV || 'development'; + +var RpcClient = require('../node_modules/bitcore/RpcClient').class(); + +var config = require('../config/config'); + +var rpc = new RpcClient(config.bitcoind); + +var block = rpc.getInfo(function(err, block) { + if (err) { + console.log("Err:"); + console.log(err); + } + + console.log("Block info:"); + console.log(block); +}); + + From 80f438fbc55311ddf8a17db0603e0b753ee5369d Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Wed, 15 Jan 2014 17:39:11 -0300 Subject: [PATCH 02/10] fix getInfo. new method getDifficulty --- app/models/Status.js | 21 +++++++++++++++++++-- test/model/status.js | 12 +++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/app/models/Status.js b/app/models/Status.js index 283032b5..2ddffc46 100644 --- a/app/models/Status.js +++ b/app/models/Status.js @@ -10,16 +10,33 @@ function spec() { function Status() { this.info = {}; + this.difficulty = {}; } Status.prototype.getInfo = function(next) { var that = this; async.series([ function (cb) { - rpc.getInfo(function(err, block){ + rpc.getInfo(function(err, info){ if (err) return cb(err); - that.info = block.result; + that.info = info.result; + return cb(); + }); + } + ], function (err) { + return next(err); + }); + }; + + Status.prototype.getDifficulty = function(next) { + var that = this; + async.series([ + function (cb) { + rpc.getDifficulty(function(err, df){ + if (err) return cb(err); + + that.difficulty = df.result; return cb(); }); } diff --git a/test/model/status.js b/test/model/status.js index 0bcd6cdc..e1c22bcc 100644 --- a/test/model/status.js +++ b/test/model/status.js @@ -25,7 +25,17 @@ describe('Status', function(){ d.getInfo(function(err) { if (err) done(err); - assert.equal(4096, d.info.difficulty); + assert.equal('number', typeof d.info.difficulty); + done(); + }); + }); + + it('getDifficulty', function(done) { + var d = new Status(); + + d.getDifficulty(function(err) { + if (err) done(err); + assert.equal('number', typeof d.difficulty); done(); }); }); From c96b6a7598451af9a987fe0421df5c2b17dca7ed Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Wed, 15 Jan 2014 18:05:02 -0300 Subject: [PATCH 03/10] method: getTxOutInfo --- app/models/Status.js | 17 +++++++++++++++++ test/model/status.js | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/app/models/Status.js b/app/models/Status.js index 2ddffc46..be5149cf 100644 --- a/app/models/Status.js +++ b/app/models/Status.js @@ -11,6 +11,7 @@ function spec() { function Status() { this.info = {}; this.difficulty = {}; + this.txoutsetinfo = {}; } Status.prototype.getInfo = function(next) { @@ -45,6 +46,22 @@ function spec() { }); }; + Status.prototype.getTxOutSetInfo = function(next) { + var that = this; + async.series([ + function (cb) { + rpc.getTxOutSetInfo(function(err, txout){ + if (err) return cb(err); + + that.txoutsetinfo = txout.result; + return cb(); + }); + } + ], function (err) { + return next(err); + }); + }; + return Status; } diff --git a/test/model/status.js b/test/model/status.js index e1c22bcc..0795ecb1 100644 --- a/test/model/status.js +++ b/test/model/status.js @@ -40,5 +40,15 @@ describe('Status', function(){ }); }); + it('getTxOutSetInfo', function(done) { + var d = new Status(); + + d.getTxOutSetInfo(function(err) { + if (err) done(err); + assert.equal('number', typeof d.txoutsetinfo.txouts); + done(); + }); + }); + }); From b2d4e3c327c4c012e46fd2c7c7172e06c3dd6a2e Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Wed, 15 Jan 2014 18:27:06 -0300 Subject: [PATCH 04/10] added getbestblockhash to Status class --- app/models/Status.js | 17 +++++++++++++++++ test/model/status.js | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/app/models/Status.js b/app/models/Status.js index be5149cf..fab5fffd 100644 --- a/app/models/Status.js +++ b/app/models/Status.js @@ -12,6 +12,7 @@ function spec() { this.info = {}; this.difficulty = {}; this.txoutsetinfo = {}; + this.bestblockhash = {}; } Status.prototype.getInfo = function(next) { @@ -62,6 +63,22 @@ function spec() { }); }; + Status.prototype.getBestBlockHash = function(next) { + var that = this; + async.series([ + function (cb) { + rpc.getBestBlockHash(function(err, bbh){ + if (err) return cb(err); + + that.bestblockhash = bbh.result; + return cb(); + }); + } + ], function (err) { + return next(err); + }); + }; + return Status; } diff --git a/test/model/status.js b/test/model/status.js index 0795ecb1..599d701a 100644 --- a/test/model/status.js +++ b/test/model/status.js @@ -50,5 +50,16 @@ describe('Status', function(){ }); }); + it('getBestBlockHash', function(done) { + var d = new Status(); + + d.getBestBlockHash(function(err) { + if (err) done(err); + assert.equal('string', typeof d.bestblockhash); + done(); + }); + }); + + }); From 60a2dfa1c21eea4d71bc08c0b7ccba9f807aed15 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 16 Jan 2014 10:51:20 -0300 Subject: [PATCH 05/10] use new bitcore RpcClient flahs --- config/env/development.js | 1 + config/env/test.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/env/development.js b/config/env/development.js index 3439a607..0d4e6c1b 100755 --- a/config/env/development.js +++ b/config/env/development.js @@ -11,6 +11,7 @@ module.exports = { pass: process.env.BITCOIND_PASS || 'real_mystery', host: process.env.BITCOIND_HOST || '127.0.0.1', port: process.env.BITCOIND_PORT || '18332', + disableAgent: true, }, network: 'testnet', } diff --git a/config/env/test.js b/config/env/test.js index 6f34e9af..abebba3b 100755 --- a/config/env/test.js +++ b/config/env/test.js @@ -12,7 +12,7 @@ module.exports = { pass: process.env.BITCOIND_PASS || 'real_mystery', host: process.env.BITCOIND_HOST || '127.0.0.1', port: process.env.BITCOIND_PORT || '18332', - keepConnectionAlive: false, + disableAgent: true, }, network: 'testnet', } From 479b262361a761cd03b6ce01fb0f6618e69d2741 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 16 Jan 2014 10:51:39 -0300 Subject: [PATCH 06/10] fix hash and time in Block sync --- app/models/Block.js | 8 +++++--- lib/Sync.js | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/models/Block.js b/app/models/Block.js index f3603ef4..17010f41 100644 --- a/app/models/Block.js +++ b/app/models/Block.js @@ -42,14 +42,16 @@ BlockSchema.path('title').validate(function(title) { * Statics */ -BlockSchema.statics.createTimestamped = function(block, cb) { +BlockSchema.statics.customCreate = function(block, cb) { var That= this; - var now = Math.round(new Date().getTime() / 1000); var BlockSchema = mongoose.model('Block', BlockSchema); + var newBlock = new That(); - newBlock.time = now; + + newBlock.time = block.time ? block.time : Math.round(new Date().getTime() / 1000); + newBlock.hash = block.blockHash; Transaction.createFromArray(block.tx, function(err, inserted_txs) { if (err) return cb(err); diff --git a/lib/Sync.js b/lib/Sync.js index 6393934f..cd0805af 100644 --- a/lib/Sync.js +++ b/lib/Sync.js @@ -113,7 +113,7 @@ function spec() { Sync.prototype.storeBlock = function(block, cb) { var that = this; - Block.createTimestamped(block, function(err, b){ + Block.customCreate(block, function(err, b){ if (b && that.opts.broadcast_blocks) { sockets.broadcast_block(b); From acb54a0190f5761e1dcb6222f9fc6fdc2b19c6b9 Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Thu, 16 Jan 2014 10:54:21 -0300 Subject: [PATCH 07/10] front-end for status network information in a new page --- app/controllers/status.js | 51 +++++++++++ app/views/includes/foot.jade | 2 + config/routes.js | 4 + public/js/app.js | 4 +- public/js/config.js | 3 + public/js/controllers/header.js | 14 +++- public/js/controllers/status.js | 26 ++++++ public/js/services/status.js | 8 ++ public/views/status.html | 144 ++++++++++++++++++++++++++++++++ 9 files changed, 251 insertions(+), 5 deletions(-) create mode 100644 app/controllers/status.js create mode 100644 public/js/controllers/status.js create mode 100644 public/js/services/status.js create mode 100644 public/views/status.html diff --git a/app/controllers/status.js b/app/controllers/status.js new file mode 100644 index 00000000..7fbc189b --- /dev/null +++ b/app/controllers/status.js @@ -0,0 +1,51 @@ +'use strict'; + +/** + * Module dependencies. + */ + +var Status = require('../models/Status'); +var async = require('async'); + +/** + * Status + */ +exports.show = function(req, res) { + + if (! req.query.q) { + res.status(400).send('Bad Request'); + } + else { + var s = req.query.q; + var d = Status.new(); + + if (s == 'getInfo') { + d.getInfo(function(err) { + if (err) next(err); + res.jsonp(d); + }); + } + else if (s == 'getDifficulty') { + d.getDifficulty(function(err) { + if (err) next(err); + res.jsonp(d); + }); + } + else if (s == 'getTxOutSetInfo') { + d.getTxOutSetInfo(function(err) { + if (err) next(err); + res.jsonp(d); + }); + } + else if (s == 'getBestBlockHash') { + d.getBestBlockHash(function(err) { + if (err) next(err); + res.jsonp(d); + }); + } + else { + res.status(400).send('Bad Request'); + } + } +}; + diff --git a/app/views/includes/foot.jade b/app/views/includes/foot.jade index 0569542d..afd82e2e 100755 --- a/app/views/includes/foot.jade +++ b/app/views/includes/foot.jade @@ -26,6 +26,7 @@ script(type='text/javascript', src='/js/directives.js') script(type='text/javascript', src='/js/filters.js') //Application Services +script(type='text/javascript', src='/js/services/status.js') script(type='text/javascript', src='/js/services/address.js') script(type='text/javascript', src='/js/services/transactions.js') script(type='text/javascript', src='/js/services/blocks.js') @@ -39,4 +40,5 @@ script(type='text/javascript', src='/js/controllers/blocks.js') script(type='text/javascript', src='/js/controllers/transactions.js') script(type='text/javascript', src='/js/controllers/address.js') script(type='text/javascript', src='/js/controllers/search.js') +script(type='text/javascript', src='/js/controllers/status.js') script(type='text/javascript', src='/js/init.js') diff --git a/config/routes.js b/config/routes.js index 51a3413c..a8a7e789 100644 --- a/config/routes.js +++ b/config/routes.js @@ -26,4 +26,8 @@ module.exports = function(app) { app.get('/api/addr/:addr', addresses.show); app.param('addr', addresses.address); + // Status route + var st = require('../app/controllers/status'); + app.get('/api/status', st.show); + }; diff --git a/public/js/app.js b/public/js/app.js index c11c807e..452ca7ce 100755 --- a/public/js/app.js +++ b/public/js/app.js @@ -13,7 +13,8 @@ var app = angular.module('mystery', 'mystery.transactions', 'monospaced.qrcode', 'mystery.address', - 'mystery.search' + 'mystery.search', + 'mystery.status' ]); angular.module('mystery.system', []); @@ -22,3 +23,4 @@ angular.module('mystery.blocks', []); angular.module('mystery.transactions', []); angular.module('mystery.address', []); angular.module('mystery.search', []); +angular.module('mystery.status', []); diff --git a/public/js/config.js b/public/js/config.js index 12813859..45fd3dc3 100755 --- a/public/js/config.js +++ b/public/js/config.js @@ -22,6 +22,9 @@ angular.module('mystery').config(['$routeProvider', when('/address/:addrStr', { templateUrl: 'views/address.html' }). + when('/status', { + templateUrl: 'views/status.html' + }). otherwise({ redirectTo: '/' }); diff --git a/public/js/controllers/header.js b/public/js/controllers/header.js index 8dddc143..53df9f8f 100755 --- a/public/js/controllers/header.js +++ b/public/js/controllers/header.js @@ -3,10 +3,16 @@ angular.module('mystery.system').controller('HeaderController', ['$scope', 'Global', function ($scope, Global) { $scope.global = Global; - $scope.menu = [{ - 'title': 'Blocks', - 'link': 'blocks' - }]; + $scope.menu = [ + { + 'title': 'Blocks', + 'link': 'blocks' + }, + { + 'title': 'Status', + 'link': 'status' + } + ]; $scope.isCollapsed = false; }]); diff --git a/public/js/controllers/status.js b/public/js/controllers/status.js new file mode 100644 index 00000000..b37a5aeb --- /dev/null +++ b/public/js/controllers/status.js @@ -0,0 +1,26 @@ +'use strict'; + +angular.module('mystery.status').controller('StatusController', ['$scope', '$routeParams', '$location', 'Global', 'Status', function ($scope, $routeParams, $location, Global, Status) { + $scope.global = Global; + + $scope.getData = function(q) { + Status.get({ + q: q + }, function(d) { + if (q == 'getInfo') { + $scope.info = d.info; + } + if (q == 'getDifficulty') { + $scope.difficulty = d.difficulty; + } + if (q == 'getTxOutSetInfo') { + $scope.txoutsetinfo = d.txoutsetinfo; + } + if (q == 'getBestBlockHash') { + $scope.bestblockhash = d.bestblockhash; + } + }); + }; + +}]); + diff --git a/public/js/services/status.js b/public/js/services/status.js new file mode 100644 index 00000000..2a066bf1 --- /dev/null +++ b/public/js/services/status.js @@ -0,0 +1,8 @@ +'use strict'; + +angular.module('mystery.status').factory('Status', ['$resource', function($resource) { + return $resource('/api/status', { + q: '@q' + }); +}]); + diff --git a/public/views/status.html b/public/views/status.html new file mode 100644 index 00000000..f28e0e40 --- /dev/null +++ b/public/views/status.html @@ -0,0 +1,144 @@ +
+ +
+
+

getInfo

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Loading...
Version{{info.version}}
protocolversion{{info.protocolversion}}
walletversion{{info.walletversion}}
balance{{info.balance}}
blocks{{info.blocks}}
timeoffset{{info.timeoffset}}
connections{{info.connections}}
proxy{{info.proxy}}
difficulty{{info.difficulty}}
testnet{{info.testnet}}
keypoololdest{{info.keypoololdest}}
keypoolsize{{info.keypoolsize}}
paytxfee{{info.paytxfee}}
errors{{info.errors}}
+
+
+

getTxOutSetInfo

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Loading...
Height{{txoutsetinfo.height}}
bestblock{{txoutsetinfo.bestblock}}
transactions{{txoutsetinfo.transactions}}
txouts{{txoutsetinfo.txouts}}
bytes_serialized{{txoutsetinfo.bytes_serialized}}
hash_serialized{{txoutsetinfo.hash_serialized}}
total_amount{{txoutsetinfo.total_amount}}
+
+
+ +
+
+

getDifficulty

+ + + + + + + + + + +
Loading...
Difficulty{{difficulty}}
+
+
+

getBestBlockHash

+ + + + + + + + + +
Loading...
{{bestblockhash}}
+
+
+
+ From 4457342af0f38aa0f724b1a9dcaecc1ef2ea9381 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 16 Jan 2014 10:54:59 -0300 Subject: [PATCH 08/10] fix block and tx times for historic --- app/models/Block.js | 2 +- app/models/Transaction.js | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/models/Block.js b/app/models/Block.js index 17010f41..a011ef9b 100644 --- a/app/models/Block.js +++ b/app/models/Block.js @@ -53,7 +53,7 @@ BlockSchema.statics.customCreate = function(block, cb) { newBlock.time = block.time ? block.time : Math.round(new Date().getTime() / 1000); newBlock.hash = block.blockHash; - Transaction.createFromArray(block.tx, function(err, inserted_txs) { + Transaction.createFromArray(block.tx, newBlock.time, function(err, inserted_txs) { if (err) return cb(err); newBlock.save(function(err) { return cb(err, inserted_txs); diff --git a/app/models/Transaction.js b/app/models/Transaction.js index 80287f5f..d1eb3b6f 100644 --- a/app/models/Transaction.js +++ b/app/models/Transaction.js @@ -87,18 +87,17 @@ TransactionSchema.statics.fromIdWithInfo = function(txid, cb) { }; -TransactionSchema.statics.createFromArray = function(txs, next) { +TransactionSchema.statics.createFromArray = function(txs, time, next) { var that = this; if (!txs) return next(); var mongo_txs = []; - var now = Math.round(new Date().getTime() / 1000); async.forEachLimit(txs, CONCURRENCY, function(txid, cb) { that.explodeTransactionItems( txid, function(err) { if (err) return next(err); - that.create({txid: txid, time: now}, function(err, new_tx) { + that.create({txid: txid, time: time}, function(err, new_tx) { if (err && ! err.toString().match(/E11000/)) return cb(err); if (new_tx) mongo_txs.push(new_tx); @@ -112,7 +111,7 @@ TransactionSchema.statics.createFromArray = function(txs, next) { }; -TransactionSchema.statics.explodeTransactionItems = function(txid, cb) { +TransactionSchema.statics.explodeTransactionItems = function(txid, time, cb) { this.queryInfo(txid, function(err, info) { if (err || !info) return cb(err); @@ -131,7 +130,7 @@ TransactionSchema.statics.explodeTransactionItems = function(txid, cb) { value_sat : -1 * i.valueSat, addr : i.addr, index : i.n, - ts : info.time, + ts : time, }, next_in); } else { @@ -155,7 +154,7 @@ TransactionSchema.statics.explodeTransactionItems = function(txid, cb) { value_sat : o.valueSat, addr : o.scriptPubKey.addresses[0], index : o.n, - ts : info.time, + ts : time, }, next_out); } else { From 2aefe7119d4ccb90b480b5052dfebd007b32c32b Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 16 Jan 2014 11:01:01 -0300 Subject: [PATCH 09/10] fix hash in block historical sync --- app/models/Block.js | 3 ++- app/models/Transaction.js | 2 +- lib/Sync.js | 2 +- test/model/transaction.js | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/models/Block.js b/app/models/Block.js index a011ef9b..d538b70a 100644 --- a/app/models/Block.js +++ b/app/models/Block.js @@ -51,10 +51,11 @@ BlockSchema.statics.customCreate = function(block, cb) { var newBlock = new That(); newBlock.time = block.time ? block.time : Math.round(new Date().getTime() / 1000); - newBlock.hash = block.blockHash; + newBlock.hash = block.hash; Transaction.createFromArray(block.tx, newBlock.time, function(err, inserted_txs) { if (err) return cb(err); + newBlock.save(function(err) { return cb(err, inserted_txs); }); diff --git a/app/models/Transaction.js b/app/models/Transaction.js index d1eb3b6f..d8971f7a 100644 --- a/app/models/Transaction.js +++ b/app/models/Transaction.js @@ -94,7 +94,7 @@ TransactionSchema.statics.createFromArray = function(txs, time, next) { async.forEachLimit(txs, CONCURRENCY, function(txid, cb) { - that.explodeTransactionItems( txid, function(err) { + that.explodeTransactionItems( txid, time, function(err) { if (err) return next(err); that.create({txid: txid, time: time}, function(err, new_tx) { diff --git a/lib/Sync.js b/lib/Sync.js index cd0805af..d4a38c1c 100644 --- a/lib/Sync.js +++ b/lib/Sync.js @@ -227,7 +227,7 @@ function spec() { } // This will trigger an RPC call - Transaction.explodeTransactionItems( tx.txid, function(err) { + Transaction.explodeTransactionItems( tx.txid, tx.time, function(err) { if (proc++ % 1000 === 0) progress_bar('\tproc', pull, total); next(err); }); diff --git a/test/model/transaction.js b/test/model/transaction.js index d42c172b..351ed2cd 100644 --- a/test/model/transaction.js +++ b/test/model/transaction.js @@ -118,7 +118,8 @@ describe('Transaction', function(){ // Remove first TransactionItem.remove({txid: v.txid}, function(err) { - Transaction.explodeTransactionItems(v.txid, function(err, tx) { + var now = Math.round(new Date().getTime() / 1000); + Transaction.explodeTransactionItems(v.txid, now, function(err, tx) { if (err) done(err); TransactionItem From 3a2d0fd34852fe5cd1b2e570563d757affc8b911 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 16 Jan 2014 13:01:32 -0300 Subject: [PATCH 10/10] fix tx_handle and -R in sync --- app/models/Block.js | 4 ++- lib/PeerSync.js | 3 +- lib/Sync.js | 88 ++++++++++++++++++++++++++++++++++----------- util/get_block.js | 2 +- util/sync.js | 7 ++-- 5 files changed, 77 insertions(+), 27 deletions(-) diff --git a/app/models/Block.js b/app/models/Block.js index d538b70a..edb80f98 100644 --- a/app/models/Block.js +++ b/app/models/Block.js @@ -26,6 +26,7 @@ var BlockSchema = new Schema({ unique: true, }, time: Number, + nextBlockHash: String, }); /** @@ -52,12 +53,13 @@ BlockSchema.statics.customCreate = function(block, cb) { newBlock.time = block.time ? block.time : Math.round(new Date().getTime() / 1000); newBlock.hash = block.hash; + newBlock.nextBlockHash = block.nextBlockHash; Transaction.createFromArray(block.tx, newBlock.time, function(err, inserted_txs) { if (err) return cb(err); newBlock.save(function(err) { - return cb(err, inserted_txs); + return cb(err, newBlock, inserted_txs); }); }); }; diff --git a/lib/PeerSync.js b/lib/PeerSync.js index e11f309b..fff731b6 100644 --- a/lib/PeerSync.js +++ b/lib/PeerSync.js @@ -57,7 +57,7 @@ function spec() { PeerSync.prototype.handle_tx = function(info) { var tx = info.message.tx.getStandardizedObject(); console.log('[p2p_sync] Handle tx: ' + tx.hash); - this.sync.storeTxs([tx.hash], function(err) { + this.sync.storeTxs([tx.hash], null, function(err) { if (err) { console.log('[p2p_sync] Error in handle TX: ' + err); } @@ -78,6 +78,7 @@ function spec() { this.sync.storeBlock({ 'hash': blockHash, 'tx': tx_hashes, + // TODO NEXT BLOCK / PREV BLOCK? }, function(err) { if (err) { diff --git a/lib/Sync.js b/lib/Sync.js index d4a38c1c..92b89afa 100644 --- a/lib/Sync.js +++ b/lib/Sync.js @@ -29,10 +29,12 @@ function spec() { }; Sync.prototype.getPrevNextBlock = function(blockHash, blockEnd, opts, cb) { + var that = this; // recursion end. if (!blockHash || (blockEnd && blockEnd == blockHash) ) { + console.log("Reach end:", blockHash, blockEnd); return cb(); } @@ -100,8 +102,9 @@ function spec() { console.log("ERROR: @%s: %s [count: block_count: %d]", blockHash, err, that.block_count); if (blockInfo && blockInfo.result) { - if (opts.prev && blockInfo.result.prevblockhash) - return that.getPrevNextBlock(blockInfo.result.prevblockhash, blockEnd, opts, cb); + if (opts.prev && blockInfo.result.previousblockhash) { + return that.getPrevNextBlock(blockInfo.result.previousblockhash, blockEnd, opts, cb); + } if (opts.next && blockInfo.result.nextblockhash) return that.getPrevNextBlock(blockInfo.result.nextblockhash, blockEnd, opts, cb); @@ -113,30 +116,53 @@ function spec() { Sync.prototype.storeBlock = function(block, cb) { var that = this; - Block.customCreate(block, function(err, b){ + Block.customCreate(block, function(err, block, inserted_txs){ - if (b && that.opts.broadcast_blocks) { - sockets.broadcast_block(b); + if (block && that.opts.broadcast_blocks) { + sockets.broadcast_block(block); } - if (that.opts.broadcast_txs) { - block.tx.each(function(tx) { - sockets.broadcast_tx(new_tx); + if (inserted_txs && that.opts.broadcast_txs) { + inserted_txs.forEach(function(tx) { + sockets.broadcast_tx(tx); }); } - that.tx_count += block.tx.length; + if (inserted_txs) + that.tx_count += inserted_txs.length; return cb(); }); }; - Sync.prototype.syncBlocks = function(start, end, cb) { + + Sync.prototype.storeTxs = function(txs, inTime, cb) { var that = this; - console.log('Syncing Blocks, starting from: %s end: %s ',start, end); + var time = inTime ? inTime : Math.round(new Date().getTime() / 1000); - return that.getPrevNextBlock(start, end, { next: 1 }, cb); + Transaction.createFromArray(txs, time, function(err, inserted_txs) { + if (!err && inserted_txs && that.opts.broadcast_txs) { + + inserted_txs.forEach(function(tx) { + sockets.broadcast_tx(tx); + }); + } + + return cb(err); + }); + }; + + + Sync.prototype.syncBlocks = function(start, end, isForward, cb) { + var that = this; + + console.log('Syncing Blocks, starting \n\tfrom: %s \n\tend: %s \n\tisForward:', + start, end, isForward); + + + return that.getPrevNextBlock( start, end, + isForward ? { next: 1 } : { prev: 1}, cb); }; // This is not currently used. Transactions are represented by txid only @@ -266,6 +292,8 @@ function spec() { var retry_attemps = 100; var retry_secs = 2; + var block_best; + this.db.once('open', function() { async.series([ function(cb) { @@ -273,7 +301,7 @@ function spec() { console.log('Deleting Blocks...'); that.db.collections.blocks.drop(cb); } else { - cb(); + return cb(); } }, function(cb) { @@ -281,7 +309,7 @@ function spec() { console.log('Deleting TXs...'); that.db.collections.transactions.drop(cb); } else { - cb(); + return cb(); } }, function(cb) { @@ -289,7 +317,7 @@ function spec() { console.log('Deleting TXItems...'); that.db.collections.transactionitems.drop(cb); } else { - cb(); + return cb(); } }, function(cb) { @@ -301,11 +329,34 @@ function spec() { }); }, function(cb) { + if (!opts.reverse) return cb(); + + that.rpc.getBestBlockHash(function(err, res) { + if (err) cb(err); + + block_best = res.result; + return cb(); + }); + }, + ], function(err) { + + function sync() { - var startingBlockHash = that.network.genesisBlock.hash.reverse().toString('hex'); + var start, end, isForward; - that.syncBlocks( startingBlockHash, null, function(err) { + if (opts.reverse) { + start = block_best; + end = that.network.genesisBlock.hash.reverse().toString('hex'); + isForward = false; + } + else { + start = that.network.genesisBlock.hash.reverse().toString('hex'); + end = null; + isForward = true; + } + + that.syncBlocks(start, end, isForward, function(err) { if (err && err.message.match(/ECONNREFUSED/) && retry_attemps--){ setTimeout(function() { @@ -321,9 +372,6 @@ function spec() { if (!opts.skip_blocks) { sync(); } - }, - ], function(err) { - return next(err, that.block_count); }); }); }; diff --git a/util/get_block.js b/util/get_block.js index 783d7cf7..0bc5955e 100755 --- a/util/get_block.js +++ b/util/get_block.js @@ -11,7 +11,7 @@ var block_hash = process.argv[2] || '0000000000b6288775bbd326bedf324ca8717a15191 var rpc = new RpcClient(config.bitcoind); -var block = rpc.getBlock(block_hash, function(err, block) { +var block = rpc.getBestBlockHash( function(err, block) { console.log("Err:"); console.log(err); diff --git a/util/sync.js b/util/sync.js index 95be4aa0..ff5d54ea 100755 --- a/util/sync.js +++ b/util/sync.js @@ -14,9 +14,8 @@ var async = require('async'); program .version(SYNC_VERSION) .option('-N --network [livenet]', 'Set bitcoin network [testnet]', 'testnet') - .option('-D --destroy', 'Remove current DB (and start from there)', '0') - .option('--skip_blocks', 'Sync blocks') - .option('--skip_txs', 'Sync transactions') + .option('-D --destroy', 'Remove current DB (and start from there)', 0) + .option('-R --reverse', 'Sync backwards', 0) .parse(process.argv); var sync = new Sync({ @@ -38,7 +37,7 @@ function(cb) { console.log('CRITICAL ERROR: ', err); } else { - console.log('Done! [%d blocks]', count); + console.log('Done! [%d blocks]', count, err); } cb(); });