From a4dd13de152c87ad2ab66140f758c5ab7a6f9f60 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 12 Feb 2014 12:39:30 -0300 Subject: [PATCH 1/7] smart by default --- util/sync.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/sync.js b/util/sync.js index 0906092e..99ddb85c 100755 --- a/util/sync.js +++ b/util/sync.js @@ -13,11 +13,11 @@ var async = require('async'); program .version(SYNC_VERSION) .option('-N --network [livenet]', 'Set bitcoin network [testnet]', 'testnet') - .option('-S --smart', 'genesis stored? uptoexisting = 1', 1) .option('-D --destroy', 'Remove current DB (and start from there)', 0) .option('-R --reverse', 'Sync backwards', 0) .option('-U --uptoexisting', 'Sync only until an existing block is found', 0) .option('-F --fromfiles', 'Sync using bitcoind .dat block files (faster)', 0) + .option('-S --smart', 'genesis stored? uptoexisting = 1, fromFiles=1 [default]', true) .option('-v --verbose', 'Verbose 0/1', 0) .parse(process.argv); @@ -34,7 +34,9 @@ async.series([ }, function(cb) { - if (program.smart) { + if (typeof program.smart === 'undefined' || parseInt(program.smart) ) { + +console.log('[sync.js.38]'); //TODO historicSync.smartImport({ destroy: program.destroy, },cb); From 65c711b27894182259ed760d953037d3a31c67b4 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 12 Feb 2014 13:11:27 -0300 Subject: [PATCH 2/7] fixes #266 and #264 --- Gruntfile.js | 4 +-- lib/HistoricSync.js | 40 +------------------------- lib/PeerSync.js | 16 +++++++++++ lib/Sync.js | 44 ++++++++++++++++++++++++++++ lib/TransactionDb.js | 8 +----- public/src/css/common.css | 21 ++++++++++++++ public/views/status.html | 60 +++++++++++++++++++-------------------- util/sync.js | 2 -- 8 files changed, 115 insertions(+), 80 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index d0d2afa8..7b04ccef 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -35,8 +35,8 @@ module.exports = function(grunt) { livereload: true, }, }, - js2: { - files: ['public/src/**/*.js'], + assets: { + files: ['public/src/**/*.js', 'public/**/*.css'], tasks: ['compile'], options: { livereload: true, diff --git a/lib/HistoricSync.js b/lib/HistoricSync.js index 4b8dcf3f..87c671ff 100644 --- a/lib/HistoricSync.js +++ b/lib/HistoricSync.js @@ -7,8 +7,6 @@ require('classtool'); function spec() { var util = require('util'); var RpcClient = require('bitcore/RpcClient').class(); - var bitutil = require('bitcore/util/util'); - var Address = require('bitcore/Address').class(); var Script = require('bitcore/Script').class(); var networks = require('bitcore/networks'); var async = require('async'); @@ -219,42 +217,6 @@ function spec() { }; - // TODO. replace with - // Script.prototype.getAddrStrs if that one get merged in bitcore - HistoricSync.prototype.getAddrStr = function(s) { - var self = this; - - var addrStrs = []; - var type = s.classify(); - var addr; - - switch(type) { - case Script.TX_PUBKEY: - var chunk = s.captureOne(); - addr = new Address(self.network.addressPubkey, bitutil.sha256ripe160(chunk)); - addrStrs = [ addr.toString() ]; - break; - case Script.TX_PUBKEYHASH: - addr = new Address(self.network.addressPubkey, s.captureOne()); - addrStrs = [ addr.toString() ]; - break; - case Script.TX_SCRIPTHASH: - addr = new Address(self.network.addressScript, s.captureOne()); - addrStrs = [ addr.toString() ]; - break; - case Script.TX_MULTISIG: - var chunks = s.capture(); - chunks.forEach(function(chunk) { - var a = new Address(self.network.addressPubkey, bitutil.sha256ripe160(chunk)); - addrStrs.push(a.toString()); - }); - break; - case Script.TX_UNKNOWN: - break; - } - - return addrStrs; - }; HistoricSync.prototype.getBlockFromFile = function(cb) { var self = this; @@ -285,7 +247,7 @@ function spec() { var s = new Script(o.s); - var addrs = self.getAddrStr(s); + var addrs = self.sync.getAddrStr(s); // support only for p2pubkey p2pubkeyhash and p2sh if (addrs.length === 1) { diff --git a/lib/PeerSync.js b/lib/PeerSync.js index c5651763..090b4de3 100644 --- a/lib/PeerSync.js +++ b/lib/PeerSync.js @@ -6,6 +6,7 @@ function spec() { var CoinConst = require('bitcore/const'); var coinUtil = require('bitcore/util/util'); var Sync = require('./Sync').class(); + var Script = require('bitcore/Script').class(); var Peer = require('bitcore/Peer').class(); var config = require('../config/config'); var networks = require('bitcore/networks'); @@ -51,8 +52,23 @@ function spec() { }; PeerSync.prototype.handleTx = function(info) { + var self =this; var tx = info.message.tx.getStandardizedObject(); console.log('[p2p_sync] Handle tx: ' + tx.hash); + tx.time = tx.time || Math.round(new Date().getTime() / 1000); + + var to=0; + info.message.tx.outs.forEach( function(o) { + var s = new Script(o.s); + var addrs = self.sync.getAddrStr(s); + + // support only for p2pubkey p2pubkeyhash and p2sh + if (addrs.length === 1) { + tx.out[to].addrStr = addrs[0]; + tx.out[to].n = to; + } + to++; + }); this.sync.storeTxs([tx], function(err) { if (err) { diff --git a/lib/Sync.js b/lib/Sync.js index d69bc120..d343fd0d 100644 --- a/lib/Sync.js +++ b/lib/Sync.js @@ -6,7 +6,12 @@ require('classtool'); function spec() { var sockets = require('../app/controllers/socket.js'); var BlockDb = require('./BlockDb').class(); + var bitutil = require('bitcore/util/util'); + var Address = require('bitcore/Address').class(); var TransactionDb = require('./TransactionDb').class(); + var config = require('../config/config'); + var networks = require('bitcore/networks'); + var Script = require('bitcore/Script').class(); var async = require('async'); @@ -18,6 +23,7 @@ function spec() { self.opts = opts; this.bDb = new BlockDb(opts); this.txDb = new TransactionDb(opts); + this.network = config.network === 'testnet' ? networks.testnet: networks.livenet; return cb(); }; @@ -276,6 +282,44 @@ function spec() { return cb(err); }); }; + + + // TODO. replace with + // Script.prototype.getAddrStrs if that one get merged in bitcore + Sync.prototype.getAddrStr = function(s) { + var self = this; + + var addrStrs = []; + var type = s.classify(); + var addr; + + switch(type) { + case Script.TX_PUBKEY: + var chunk = s.captureOne(); + addr = new Address(self.network.addressPubkey, bitutil.sha256ripe160(chunk)); + addrStrs = [ addr.toString() ]; + break; + case Script.TX_PUBKEYHASH: + addr = new Address(self.network.addressPubkey, s.captureOne()); + addrStrs = [ addr.toString() ]; + break; + case Script.TX_SCRIPTHASH: + addr = new Address(self.network.addressScript, s.captureOne()); + addrStrs = [ addr.toString() ]; + break; + case Script.TX_MULTISIG: + var chunks = s.capture(); + chunks.forEach(function(chunk) { + var a = new Address(self.network.addressPubkey, bitutil.sha256ripe160(chunk)); + addrStrs.push(a.toString()); + }); + break; + case Script.TX_UNKNOWN: + break; + } + + return addrStrs; + }; return Sync; } module.defineClass(spec); diff --git a/lib/TransactionDb.js b/lib/TransactionDb.js index 05b3e46f..a06ae455 100644 --- a/lib/TransactionDb.js +++ b/lib/TransactionDb.js @@ -442,13 +442,7 @@ function spec(b) { .write(next_out); }, function (err) { - if (err) { - if (!err.message.match(/E11000/)) { - console.log('ERR at TX %s: %s', tx.txid, err); - return cb(err); - } - } - return p_c(); + return p_c(err); }); }, // Parse Outputs diff --git a/public/src/css/common.css b/public/src/css/common.css index 4e8ea714..c8e24c1f 100644 --- a/public/src/css/common.css +++ b/public/src/css/common.css @@ -557,3 +557,24 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { width: 20%; } +@keyframes rotateThis { + from { transform: scale( 1 ) rotate( 0deg ); } + to { transform: scale( 1 ) rotate( 360deg ); } +} + +@-webkit-keyframes rotateThis { + from { -webkit-transform: scale( 1 ) rotate( 0deg ); } + to { -webkit-transform: scale( 1 ) rotate( 360deg ); } +} + +.icon-rotate { + animation-name: rotateThis; + animation-duration: 2s; + animation-iteration-count: infinite; + animation-timing-function: linear; + -webkit-animation-name: rotateThis; + -webkit-animation-duration: 2s; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: linear; +} + diff --git a/public/views/status.html b/public/views/status.html index 7f7f4e23..a8403623 100644 --- a/public/views/status.html +++ b/public/views/status.html @@ -42,8 +42,31 @@ +

Last Block

+ + + + + + + + + + + + +
Last Block Hash (Bitcoind){{lastblockhash}}
Current Blockchain Tip(Insight){{syncTipHash}}
+ +

Transaction Output Set Information

- + +
+ + +
@@ -76,23 +99,12 @@
+ -

Last Block

- - - - - - - - - - - - -
Last Block Hash (Bitcoind){{lastblockhash}}
Current Blockchain Tip(Insight){{syncTipHash}}
+ +

Bitcoin node information

@@ -118,11 +130,7 @@ - - - - - + @@ -131,16 +139,8 @@ - - - - - - - - - - + + diff --git a/util/sync.js b/util/sync.js index 99ddb85c..02da6609 100755 --- a/util/sync.js +++ b/util/sync.js @@ -35,8 +35,6 @@ async.series([ function(cb) { if (typeof program.smart === 'undefined' || parseInt(program.smart) ) { - -console.log('[sync.js.38]'); //TODO historicSync.smartImport({ destroy: program.destroy, },cb); From 2271a11e37af87531b76e88462068fe761a423b7 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 12 Feb 2014 13:25:01 -0300 Subject: [PATCH 3/7] fixes #251 --- public/views/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/views/index.html b/public/views/index.html index 7673a13f..b38eb1be 100644 --- a/public/views/index.html +++ b/public/views/index.html @@ -62,7 +62,7 @@ and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by bitcoind RPC. Check out the source code.

-

Insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.

+

Insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.

Powered by From d561c191e70fcc18503015aab9fcce8a0f045f34 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 12 Feb 2014 13:35:57 -0300 Subject: [PATCH 4/7] sync status --- public/views/includes/header.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/public/views/includes/header.html b/public/views/includes/header.html index 888b4395..0a8252f8 100644 --- a/public/views/includes/header.html +++ b/public/views/includes/header.html @@ -25,8 +25,14 @@
  • - ERROR - {{sync.status}} {{sync.syncPercentage}}% + + + ERROR + + + + {{sync.status}} {{sync.syncPercentage}}% + On sync · From a35fcc776dff1a8bd601e6ec53653aefe6c8fe70 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 12 Feb 2014 19:27:29 -0300 Subject: [PATCH 5/7] addr tx orderer by TS. keep unconfirmed balance. fix times in txs --- app/controllers/socket.js | 5 ++- app/models/Address.js | 51 +++++++++++++++++++++++++++---- lib/HistoricSync.js | 9 +++--- lib/TransactionDb.js | 32 +++++++++++++------ public/src/js/services/socket.js | 5 ++- public/views/address.html | 5 +++ public/views/includes/header.html | 7 +++-- public/views/transaction.html | 9 +++++- public/views/transaction/tx.html | 8 ++++- test/integration/addr.json | 2 +- 10 files changed, 105 insertions(+), 28 deletions(-) diff --git a/app/controllers/socket.js b/app/controllers/socket.js index 603c7ee1..ebdce591 100644 --- a/app/controllers/socket.js +++ b/app/controllers/socket.js @@ -43,5 +43,8 @@ module.exports.broadcastAddressTx = function(address, tx) { }; module.exports.broadcastSyncInfo = function(historicSync) { - if (ios) ios.sockets.in('sync').emit('status', historicSync); + + if (ios) { + ios.sockets.in('sync').emit('status', historicSync); + } }; diff --git a/app/models/Address.js b/app/models/Address.js index cdb820b8..28ec0184 100644 --- a/app/models/Address.js +++ b/app/models/Address.js @@ -13,6 +13,9 @@ function spec() { this.balanceSat = 0; this.totalReceivedSat = 0; this.totalSentSat = 0; + + this.unconfirmedBalanceSat = 0; + this.txApperances = 0; // TODO store only txids? +index? +all? @@ -51,12 +54,25 @@ function spec() { }, enumerable: 1, }); + + + Object.defineProperty(this, 'unconfirmedBalance', { + get: function() { + return parseFloat(this.unconfirmedBalanceSat) / parseFloat(BitcoreUtil.COIN); + }, + set: function(i) { + this.unconfirmedBalanceSat = i * BitcoreUtil.COIN; + }, + enumerable: 1, + }); + } Address.prototype.update = function(next) { var self = this; if (!self.addrStr) return next(); + var txs = []; var db = new TransactionDb(); async.series([ function (cb) { @@ -64,27 +80,50 @@ function spec() { if (err) return cb(err); txOut.forEach(function(txItem){ + var v = txItem.value_sat; + + txs.push({txid: txItem.txid, ts: txItem.ts}); + self.txApperances += 1; + + if (txItem.spendTxId) { + txs.push({txid: txItem.spendTxId, ts: txItem.spendTs}); + self.txApperances += 1; + } + if (txItem.isConfirmed) { - var v = txItem.value_sat; self.totalReceivedSat += v; - self.transactions.push(txItem.txid); - if (! txItem.spendTxId || !txItem.spendIsConfirmed) { + if (! txItem.spendTxId ) { + //unspend + self.balanceSat += v; + } + else if(!txItem.spendIsConfirmed) { // unspent self.balanceSat += v; - self.txApperances +=1; + self.unconfirmedBalanceSat -= v; } else { // spent self.totalSentSat += v; - self.transactions.push(txItem.spendTxId); - self.txApperances +=2; } } + else { + self.unconfirmedBalanceSat += v; + } }); return cb(); }); }, ], function (err) { + + // sort input and outputs togheter + txs.sort( + function compare(a,b) { + if (a.ts < b.ts) return 1; + if (a.ts > b.ts) return -1; + return 0; + }); + + self.transactions = txs.map(function(i) { return i.txid; } ); return next(err); }); }; diff --git a/lib/HistoricSync.js b/lib/HistoricSync.js index 87c671ff..826fc05e 100644 --- a/lib/HistoricSync.js +++ b/lib/HistoricSync.js @@ -104,13 +104,14 @@ function spec() { HistoricSync.prototype.showProgress = function() { var self = this; - if ( ( self.syncedBlocks + self.skippedBlocks) % self.step !== 1) return; + if ( self.status ==='syncing' && + ( self.syncedBlocks + self.skippedBlocks) % self.step !== 1) return; if (self.error) { p('ERROR: ' + self.error); } else { - self.syncPercentage = parseFloat(100 * (self.syncedBlocks + self.skippedBlocks) / self.blockChainHeight).toFixed(3); + self.syncPercentage = parseFloat(100 * self.syncedBlocks / self.blockChainHeight).toFixed(3); if (self.syncPercentage > 100) self.syncPercentage = 100; p(util.format('status: [%d%%] skipped: %d ', self.syncPercentage, self.skippedBlocks)); @@ -193,7 +194,6 @@ function spec() { (blockEnd && blockEnd === blockHash)) { self.status = 'finished'; p('DONE. Found block: ', blockHash); - self.showProgress(); return cb(err); } @@ -266,7 +266,6 @@ function spec() { var self = this; self.showProgress(); - self.getBlockFromFile(function(err, blockInfo) { if (err) { self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]', @@ -406,12 +405,14 @@ function spec() { }); }); }, function(err) { + self.showProgress(); return next(err); }); } else { self.type = 'from RPC calls'; self.getPrevNextBlock(start, end, scanOpts, function(err) { + self.showProgress(); return next(err); }); } diff --git a/lib/TransactionDb.js b/lib/TransactionDb.js index a06ae455..50f55a47 100644 --- a/lib/TransactionDb.js +++ b/lib/TransactionDb.js @@ -69,7 +69,7 @@ function spec(b) { }); }; - TransactionDb.prototype._addSpendInfo = function(r, txid, index) { + TransactionDb.prototype._addSpendInfo = function(r, txid, index, ts) { if (r.spendTxId) { if (!r.multipleSpendAttempts) { r.multipleSpendAttempts = [{ @@ -85,6 +85,7 @@ function spec(b) { else { r.spendTxId = txid; r.spendIndex = parseInt(index); + r.spendTs = parseInt(ts); } }; @@ -123,7 +124,7 @@ function spec(b) { assert(typeof j !== 'undefined','Spent could not be stored: tx ' + txid + 'spend in TX:' + k[2] + ',' + k[3]+ ' j:' + j); - self._addSpendInfo(ret[j], k[4], k[5]); + self._addSpendInfo(ret[j], k[4], k[5], data.value); }) .on('error', function (err) { return cb(err); @@ -144,7 +145,7 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - self._addSpendInfo(info.vout[k[3]], k[4], k[5]); + self._addSpendInfo(info.vout[k[3]], k[4], k[5], data.value); }) .on('error', function (err) { return cb(err); @@ -162,6 +163,7 @@ function spec(b) { var valueIn = 0; var incompleteInputs = 0; + var ts; async.eachLimit(info.vin, CONCURRENCY, function(i, c_in) { self.fromTxIdN(i.txid, i.vout, function(err, ret) { @@ -203,6 +205,8 @@ function spec(b) { i.doubleSpendTxID = null; } + info.firstSeenTs = i.spendTs; + valueIn += i.valueSat; return c_in(); }); @@ -264,7 +268,7 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - self._addSpendInfo(ret, k[4], k[5]); + self._addSpendInfo(ret, k[4], k[5], data.value); }) .on('error', function (error) { return cb(error); @@ -336,7 +340,7 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - self._addSpendInfo(o, k[4], k[5]); + self._addSpendInfo(o, k[4], k[5], data.value); }) .on('error', function (err) { return e_c(err); @@ -461,12 +465,20 @@ function spec(b) { var addr = o.scriptPubKey.addresses[0]; var sat = Math.round(o.value * util.COIN); - db.batch() - .put( OUTS_PREFIX + tx.txid + '-' + o.n, addr + ':' + sat) - .put( ADDR_PREFIX + addr + '-' + ts + '-' + tx.txid + - '-' + o.n, sat) - .write(next_out); + // existed? + db.get(OUTS_PREFIX + tx.txid + '-' + o.n, function (err,val) { + if (!val) { + db.batch() + .put( OUTS_PREFIX + tx.txid + '-' + o.n, addr + ':' + sat) + .put( ADDR_PREFIX + addr + '-' + ts + '-' + tx.txid + + '-' + o.n, sat) + .write(next_out); + } + else { + return next_out(); + } + }); } else { //console.log ('WARN in TX: %s could not parse OUTPUT %d', tx.txid, o.n); diff --git a/public/src/js/services/socket.js b/public/src/js/services/socket.js index 9a2d459e..a2bf1e48 100644 --- a/public/src/js/services/socket.js +++ b/public/src/js/services/socket.js @@ -48,7 +48,10 @@ ScopedSocket.prototype.emit = function(event, data, callback) { angular.module('insight.socket').factory('getSocket', function($rootScope) { - var socket = io.connect(); + var socket = io.connect(null, { + 'reconnect': true, + 'reconnection delay': 500, +}); return function(scope) { var scopedSocket = new ScopedSocket(socket, $rootScope); scope.$on('$routeChangeStart', function() { diff --git a/public/views/address.html b/public/views/address.html index 4c5e9df6..0771f47c 100644 --- a/public/views/address.html +++ b/public/views/address.html @@ -26,6 +26,11 @@
  • + + + + + diff --git a/public/views/includes/header.html b/public/views/includes/header.html index 0a8252f8..f92bdea3 100644 --- a/public/views/includes/header.html +++ b/public/views/includes/header.html @@ -24,7 +24,7 @@ - + + + + + + + +
    Connections to other nodes {{info.connections}}
    Proxy setting{{info.proxy}}
    Mining Difficulty {{info.difficulty}}
    {{info.testnet}}
    Keypool Oldest Date{{info.keypoololdest*1000 | date:'medium' }}
    Keypool Size{{info.keypoolsize}}
    Default Transaction Fee (BTC){{info.paytxfee}}Proxy setting{{info.proxy}}
    Info ErrorsFinal Balance {{$root.currency.getConvertion(address.balance)}}
    Unconfirmed Tx Balance{{$root.currency.getConvertion(address.unconfirmedBalance)}}
    No. Transactions {{address.txApperances}}
    Received Time {{tx.time * 1000|date:'medium'}}{{tx.firstSeenTs * 1000|date:'medium'}}N/A
    Mined Time {{tx.time * 1000|date:'medium'}}N/A
    diff --git a/public/views/transaction/tx.html b/public/views/transaction/tx.html index e0cecaaa..5afaa090 100644 --- a/public/views/transaction/tx.html +++ b/public/views/transaction/tx.html @@ -6,7 +6,13 @@ {{tx.txid}}
    -
    + +
    + first seen at + +
    +
    + mined at
    diff --git a/test/integration/addr.json b/test/integration/addr.json index 9de33e9b..58dee9f7 100644 --- a/test/integration/addr.json +++ b/test/integration/addr.json @@ -43,7 +43,7 @@ }, { "addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29", - "txApperances": 2041, + "txApperances": 6049, "balance": 1199.74393853, "totalReceived": 1199.74393853, "totalSent": 0 From 6cef1eaec3c91d965902dcf4dacce615157a8459 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 12 Feb 2014 23:37:01 -0300 Subject: [PATCH 6/7] uptoexisting -> to to tip block --- lib/HistoricSync.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/HistoricSync.js b/lib/HistoricSync.js index 826fc05e..180eb101 100644 --- a/lib/HistoricSync.js +++ b/lib/HistoricSync.js @@ -320,6 +320,7 @@ function spec() { var self = this; var lastBlock; + var tip; async.series([ function(cb) { @@ -333,7 +334,6 @@ function spec() { function (cb) { return self.getBlockCount(cb); }, function(cb) { if (!scanOpts.reverse) return cb(); - self.rpc.getBlockHash(self.blockChainHeight, function(err, res) { if (err) return cb(err); lastBlock = res.result; @@ -341,6 +341,17 @@ function spec() { return cb(); }); }, + function(cb) { + if (!scanOpts.reverse) return cb(); + self.sync.bDb.getTip(function(err, res) { + if (err) return cb(err); + tip = res; + + console.log('Old Tip:', tip); + return cb(); + }); + }, + function(cb) { if (scanOpts.upToExisting) { // should be isOrphan = true or null to be more accurate. @@ -378,7 +389,7 @@ function spec() { if (scanOpts.reverse) { start = lastBlock; - end = self.genesis; + end = tip || self.genesis; scanOpts.prev = true; } else { From 09e3e1d32f03dac7e47685c1a46071dd10d0ac30 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 12 Feb 2014 23:56:52 -0300 Subject: [PATCH 7/7] new levelDB roots. test updated --- app/controllers/blocks.js | 14 ++++------- app/models/Address.js | 13 ++++++---- lib/BlockDb.js | 18 +++++++------- lib/TransactionDb.js | 45 +++++++++++++++++------------------ public/views/address.html | 25 ++++++++++++++----- test/integration/addr.js | 2 ++ test/integration/addr.json | 4 ++-- test/integration/txitems.json | 8 +++---- util/sync.js | 2 +- 9 files changed, 71 insertions(+), 60 deletions(-) diff --git a/app/controllers/blocks.js b/app/controllers/blocks.js index 04a3746b..09e90fe6 100644 --- a/app/controllers/blocks.js +++ b/app/controllers/blocks.js @@ -107,22 +107,18 @@ exports.list = function(req, res) { res.status(500).send(err); } else { - var blockshashList = []; var limit = parseInt(req.query.limit || blocks.length); if (blocks.length < limit) { limit = blocks.length; } - for(var i=0;i => - var PREV_PREFIX = 'b-prev-'; // b-prev- => - var NEXT_PREFIX = 'b-next-'; // b-next- => - var MAIN_PREFIX = 'b-main-'; // b-main- => 1/0 - var TIP = 'b-tip-'; // last block on the chain + var TIMESTAMP_PREFIX = 'bts-'; // b-ts- => + var PREV_PREFIX = 'bpr-'; // b-prev- => + var NEXT_PREFIX = 'bne-'; // b-next- => + var MAIN_PREFIX = 'bma-'; // b-main- => 1/0 + var TIP = 'bti-'; // last block on the chain /** @@ -125,14 +125,11 @@ function spec(b) { BlockDb.prototype.has = function(hash, cb) { var k = PREV_PREFIX + hash; db.get(k, function (err,val) { - var ret; + var ret = true; if (err && err.notFound) { err = null; ret = false; } - if (typeof val !== 'undefined') { - ret = true; - } return cb(err, ret); }); }; @@ -170,8 +167,9 @@ function spec(b) { fillCache: true }) .on('data', function (data) { + var k = data.key.split('-'); list.push({ - ts: data.key.replace(TIMESTAMP_PREFIX, ''), + ts: k[1], hash: data.value, }); }) diff --git a/lib/TransactionDb.js b/lib/TransactionDb.js index 50f55a47..607d10c9 100644 --- a/lib/TransactionDb.js +++ b/lib/TransactionDb.js @@ -6,17 +6,17 @@ require('classtool'); function spec(b) { // blockHash -> txid mapping - var IN_BLK_PREFIX = 'tx-b-'; //tx-b-- => 1/0 (connected or not) + var IN_BLK_PREFIX = 'txb-'; //txb-- => 1/0 (connected or not) // Only for orphan blocks var FROM_BLK_PREFIX = 'tx-'; //tx-- => 1 // to show tx outs - var OUTS_PREFIX = 'txouts-'; //txouts-- => [addr, btc_sat] + var OUTS_PREFIX = 'txo-'; //txo-- => [addr, btc_sat] + var SPEND_PREFIX = 'txs-'; //txs---- = ts - // to sum up addr balance - var ADDR_PREFIX = 'txouts-addr-'; //txouts-addr---- => + btc_sat - var SPEND_PREFIX = 'txouts-spend-';//txouts-spend---- = ts + // to sum up addr balance (only outs, spends are gotten later) + var ADDR_PREFIX = 'txa-'; //txa--- => + btc_sat:ts // TODO: use bitcore networks module var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'; @@ -119,12 +119,12 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - var j = idx[parseInt(k[3])]; + var j = idx[parseInt(k[2])]; assert(typeof j !== 'undefined','Spent could not be stored: tx ' + txid + - 'spend in TX:' + k[2] + ',' + k[3]+ ' j:' + j); + 'spend in TX:' + k[1] + ',' + k[2]+ ' j:' + j); - self._addSpendInfo(ret[j], k[4], k[5], data.value); + self._addSpendInfo(ret[j], k[3], k[4], data.value); }) .on('error', function (err) { return cb(err); @@ -145,7 +145,7 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - self._addSpendInfo(info.vout[k[3]], k[4], k[5], data.value); + self._addSpendInfo(info.vout[k[2]], k[3], k[4], data.value); }) .on('error', function (err) { return cb(err); @@ -163,7 +163,6 @@ function spec(b) { var valueIn = 0; var incompleteInputs = 0; - var ts; async.eachLimit(info.vin, CONCURRENCY, function(i, c_in) { self.fromTxIdN(i.txid, i.vout, function(err, ret) { @@ -175,6 +174,7 @@ function spec(b) { return c_in(); // error not scalated } + info.firstSeenTs = ret.spendTs; i.unconfirmedInput = i.unconfirmedInput; i.addr = ret.addr; i.valueSat = ret.valueSat; @@ -205,8 +205,6 @@ function spec(b) { i.doubleSpendTxID = null; } - info.firstSeenTs = i.spendTs; - valueIn += i.valueSat; return c_in(); }); @@ -268,7 +266,7 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - self._addSpendInfo(ret, k[4], k[5], data.value); + self._addSpendInfo(ret, k[3], k[4], data.value); }) .on('error', function (error) { return cb(error); @@ -324,10 +322,10 @@ function spec(b) { var k = data.key.split('-'); var v = data.value.split(':'); ret.push({ + txid: k[2], + index: parseInt(k[3]), value_sat: parseInt(v[0]), - ts: parseInt(k[3]), - txid: k[4], - index: parseInt(k[5]), + ts: parseInt(v[1]), }); }) .on('error', function (err) { @@ -340,7 +338,7 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - self._addSpendInfo(o, k[4], k[5], data.value); + self._addSpendInfo(o, k[3], k[4], data.value); }) .on('error', function (err) { return e_c(err); @@ -442,7 +440,8 @@ function spec(b) { async.forEachLimit(tx.vin, CONCURRENCY, function(i, next_out) { db.batch() - .put( SPEND_PREFIX + i.txid + '-' + i.vout + '-' + tx.txid + '-' + i.n, ts || 0) + .put( SPEND_PREFIX + i.txid + '-' + i.vout + '-' + tx.txid + '-' + i.n, + ts || 0) .write(next_out); }, function (err) { @@ -467,12 +466,12 @@ function spec(b) { var sat = Math.round(o.value * util.COIN); // existed? - db.get(OUTS_PREFIX + tx.txid + '-' + o.n, function (err,val) { - if (!val) { + var k = OUTS_PREFIX + tx.txid + '-' + o.n; + db.get(k, function(err) { + if (err && err.notFound) { db.batch() - .put( OUTS_PREFIX + tx.txid + '-' + o.n, addr + ':' + sat) - .put( ADDR_PREFIX + addr + '-' + ts + '-' + tx.txid + - '-' + o.n, sat) + .put( k, addr + ':' + sat) + .put( ADDR_PREFIX + addr + '-' + tx.txid + '-' + o.n, sat+':'+ts) .write(next_out); } else { diff --git a/public/views/address.html b/public/views/address.html index 0771f47c..d2f050ac 100644 --- a/public/views/address.html +++ b/public/views/address.html @@ -12,6 +12,7 @@

    Summary

    +
    Confirmed
    @@ -26,17 +27,29 @@ - - - - - - +
    Final Balance {{$root.currency.getConvertion(address.balance)}}
    Unconfirmed Tx Balance{{$root.currency.getConvertion(address.unconfirmedBalance)}}
    No. Transactions {{address.txApperances}}
    +
    +
    Unconfirmed
    + + + + + + + + + + + + +
    Unconfirmed Txs Balance{{$root.currency.getConvertion(address.unconfirmedBalance)}}
    No. Transactions{{address.unconfirmedTxApperances}}
    +
    +
    diff --git a/test/integration/addr.js b/test/integration/addr.js index 944a60e0..89db2b4d 100644 --- a/test/integration/addr.js +++ b/test/integration/addr.js @@ -30,6 +30,8 @@ describe('Address balances', function() { a.update(function(err) { if (err) done(err); assert.equal(v.addr, a.addrStr); + assert.equal(a.unconfirmedTxApperances ,0, 'unconfirmedTxApperances: 0'); + assert.equal(a.unconfirmedBalanceSat ,0, 'unconfirmedBalanceSat: 0'); if (v.txApperances) assert.equal(v.txApperances, a.txApperances, 'txApperances: ' + a.txApperances); if (v.totalReceived) assert.equal(v.totalReceived, a.totalReceived, 'received: ' + a.totalReceived); diff --git a/test/integration/addr.json b/test/integration/addr.json index 58dee9f7..b9850850 100644 --- a/test/integration/addr.json +++ b/test/integration/addr.json @@ -43,10 +43,10 @@ }, { "addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29", - "txApperances": 6049, "balance": 1199.74393853, "totalReceived": 1199.74393853, - "totalSent": 0 + "totalSent": 0, + "txApperances": 5763 }, { "addr": "mjRmkmYzvZN3cA3aBKJgYJ65epn3WCG84H", diff --git a/test/integration/txitems.json b/test/integration/txitems.json index bee3b43f..283e8733 100644 --- a/test/integration/txitems.json +++ b/test/integration/txitems.json @@ -6,8 +6,8 @@ { "txid": "21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237", "toRm": [ - "txouts-spend-86a03cac7d87f596008c6d5a8d3fd8b88842932ea6f0337673eda16f6b472f7f-0", - "txouts-spend-bcd8da8ee847da377f8aaca92502c05e5f914c6a2452753146013b0e642a25a0-0" + "txs-86a03cac7d87f596008c6d5a8d3fd8b88842932ea6f0337673eda16f6b472f7f-0", + "txs-bcd8da8ee847da377f8aaca92502c05e5f914c6a2452753146013b0e642a25a0-0" ], "items": [ { @@ -25,7 +25,7 @@ { "txid": "b633a6249d4a2bc123e7f8a151cae2d4afd17aa94840009f8697270c7818ceee", "toRm": [ - "txouts-spend-01621403689cb4a95699a3dbae029d7031c5667678ef14e2054793954fb27917-0" + "txs-01621403689cb4a95699a3dbae029d7031c5667678ef14e2054793954fb27917-0" ], "items": [ { @@ -43,7 +43,7 @@ { "txid": "ca2f42e44455b8a84434de139efea1fe2c7d71414a8939e0a20f518849085c3b", "toRm": [ - "txouts-spend-2d7b680fb06e4d7eeb65ca49ac7522276586e0090b7fe662fc708129429c5e6a-0" + "txs-2d7b680fb06e4d7eeb65ca49ac7522276586e0090b7fe662fc708129429c5e6a-0" ], "items": [ { diff --git a/util/sync.js b/util/sync.js index 02da6609..27aed0d2 100755 --- a/util/sync.js +++ b/util/sync.js @@ -15,7 +15,7 @@ program .option('-N --network [livenet]', 'Set bitcoin network [testnet]', 'testnet') .option('-D --destroy', 'Remove current DB (and start from there)', 0) .option('-R --reverse', 'Sync backwards', 0) - .option('-U --uptoexisting', 'Sync only until an existing block is found', 0) + .option('-U --uptoexisting', 'Sync only until old Tip block is found', 0) .option('-F --fromfiles', 'Sync using bitcoind .dat block files (faster)', 0) .option('-S --smart', 'genesis stored? uptoexisting = 1, fromFiles=1 [default]', true) .option('-v --verbose', 'Verbose 0/1', 0)