From 0bbc9763b2cfeb8738191732d13343b79d369545 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 10 Feb 2014 11:00:31 -0300 Subject: [PATCH 1/6] shows orphan status on block page --- lib/BlockDb.js | 15 ++++++++++++--- public/views/block.html | 4 +++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/BlockDb.js b/lib/BlockDb.js index c83cd4bf..004b9be0 100644 --- a/lib/BlockDb.js +++ b/lib/BlockDb.js @@ -139,6 +139,8 @@ function spec(b) { BlockDb.prototype.fromHashWithInfo = function(hash, cb) { + var self = this; + rpc.getBlock(hash, function(err, info) { // Not found? if (err && err.code === -5) return cb(); @@ -146,9 +148,16 @@ function spec(b) { if (info.result.height) info.result.reward = BitcoreBlock.getBlockValue(info.result.height) / util.COIN ; - return cb(null, { - hash: hash, - info: info.result, + + self.isMain(hash, function(err, val) { + if (err) return cb(err); + + info.result.isMainChain = val ? true : false; + + return cb(null, { + hash: hash, + info: info.result, + }); }); }); }; diff --git a/public/views/block.html b/public/views/block.html index 09646fd9..8a67400b 100644 --- a/public/views/block.html +++ b/public/views/block.html @@ -45,7 +45,9 @@ Height - {{block.height}} + {{block.height}} + (Mainchain) + (Orphaned) Block Reward From 7496fc47de0cd3a059a75e12e3c8a8c419f9228a Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 10 Feb 2014 14:09:28 -0300 Subject: [PATCH 2/6] index for output spend matching (speeds ups tx api --- lib/TransactionDb.js | 21 +++++++++---------- ...99-sync.js => 99-sync.js.descructive-test} | 0 test/integration/addr.json | 6 +++--- 3 files changed, 13 insertions(+), 14 deletions(-) rename test/integration/{99-sync.js => 99-sync.js.descructive-test} (100%) diff --git a/lib/TransactionDb.js b/lib/TransactionDb.js index 3b4ee25c..4f1dbe46 100644 --- a/lib/TransactionDb.js +++ b/lib/TransactionDb.js @@ -74,6 +74,8 @@ function spec(b) { var k = OUTS_PREFIX + txid; var ret=[]; + var idx={}; + var i = 0; // outs. db.createReadStream({start: k, end: k + '~'}) @@ -85,27 +87,24 @@ function spec(b) { value_sat: parseInt(v[1]), index: parseInt(k[2]), }); + idx[parseInt(k[2])]= i++; }) .on('error', function (err) { return cb(err); }) .on('end', function () { var k = SPEND_PREFIX + txid; - var l = ret.length; db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); var v = data.value.split(':'); - var set=0; - for(var i=0; i Date: Mon, 10 Feb 2014 14:10:49 -0300 Subject: [PATCH 3/6] index for output spend matching (speeds ups tx api --- lib/TransactionDb.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/TransactionDb.js b/lib/TransactionDb.js index 4f1dbe46..06a558b1 100644 --- a/lib/TransactionDb.js +++ b/lib/TransactionDb.js @@ -103,8 +103,15 @@ function spec(b) { assert(typeof j !== 'undefined','Spent could not be stored: tx ' + txid + 'spend in TX:' + k[2] + ',' + k[3]+ ' j:' + j); - ret[j].spendTxId = v[0]; - ret[j].spendIndex = parseInt(v[1]); +/// TODO Handle multiple addresses here! + if (ret[j].spendTxId) { + // double spend! + assert(0); + } + else { + ret[j].spendTxId = v[0]; + ret[j].spendIndex = parseInt(v[1]); + } }) .on('error', function (err) { return cb(err); From 9910fa4d4079a541c53666cf1549b1349f771edc Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 10 Feb 2014 15:49:33 -0300 Subject: [PATCH 4/6] fix rounding errs at valueOut --- lib/TransactionRpc.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/TransactionRpc.js b/lib/TransactionRpc.js index 0eaef276..01f4679e 100644 --- a/lib/TransactionRpc.js +++ b/lib/TransactionRpc.js @@ -32,11 +32,11 @@ function spec(b) { }); // Outputs - var valueOut = 0; + var valueOutSat = 0; info.vout.forEach( function(o) { - valueOut += o.value; + valueOutSat += o.value * util.COIN; }); - info.valueOut = valueOut; + info.valueOut = parseInt(valueOutSat) / util.COIN; info.size = b.length; return info; From 8b892edfbc64fdb5b20323040151ff88c6e95fb2 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 10 Feb 2014 15:50:07 -0300 Subject: [PATCH 5/6] new txout-spend- schema --- lib/TransactionDb.js | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/TransactionDb.js b/lib/TransactionDb.js index 06a558b1..a93d0dd9 100644 --- a/lib/TransactionDb.js +++ b/lib/TransactionDb.js @@ -16,7 +16,7 @@ function spec(b) { // to sum up addr balance var ADDR_PREFIX = 'txouts-addr-'; //txouts-addr---- => + btc_sat - var SPEND_PREFIX = 'txouts-spend-';//txouts-spend-- => [txid(in),n(in),ts] + var SPEND_PREFIX = 'txouts-spend-';//txouts-spend---- = ts // TODO: use bitcore networks module var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'; @@ -97,7 +97,6 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - var v = data.value.split(':'); var j = idx[parseInt(k[3])]; assert(typeof j !== 'undefined','Spent could not be stored: tx ' + txid + @@ -109,8 +108,8 @@ function spec(b) { assert(0); } else { - ret[j].spendTxId = v[0]; - ret[j].spendIndex = parseInt(v[1]); + ret[j].spendTxId = k[4]; + ret[j].spendIndex = parseInt(k[5]); } }) .on('error', function (err) { @@ -236,16 +235,26 @@ function spec(b) { async.each(ret, function(o, e_c) { var k = SPEND_PREFIX + o.txid + '-' + o.index; - db.get(k, function(err, val) { - if (err && err.notFound) err=null; - if (err || !val) return e_c(err); - - var v = val.split(':'); - o.spendTxId= v[0]; - o.spendIndex=parseInt(v[1]); - o.spendTs=parseInt(v[2]); - return e_c(); - }); + db.createReadStream({start: k, end: k + '~'}) + .on('data', function (data) { + var k = data.key.split('-'); + var v = data.value; + if (o.spendTxId) { + // double spend! + assert(0); + } + else { + o.spendTxId = k[4]; + o.spendIndex = parseInt(k[5]); + o.spendTs = parseInt(v); + } + }) + .on('error', function (err) { + return e_c(err); + }) + .on('end', function (err) { + return e_c(err); + }); }, function() { async.each(ret, function(o, e_c){ @@ -341,8 +350,7 @@ 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) + .put( SPEND_PREFIX + i.txid + '-' + i.vout + '-' + tx.txid + '-' + i.n, ts) .write(next_out); }, function (err) { From a920abdcd917d0f9e0ac302753e68246cf3cbf6e Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 10 Feb 2014 17:12:40 -0300 Subject: [PATCH 6/6] handle double spends --- lib/TransactionDb.js | 82 ++++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/lib/TransactionDb.js b/lib/TransactionDb.js index a93d0dd9..e5ac6ee6 100644 --- a/lib/TransactionDb.js +++ b/lib/TransactionDb.js @@ -70,8 +70,29 @@ function spec(b) { }); }; - TransactionDb.prototype.fromTxId = function(txid, cb) { + TransactionDb.prototype._addSpendInfo = function(r, txid, index) { + if (r.spendTxId) { + if (!r.multipleSpendAttempts) { + r.multipleSpendAttempts = [{ + txid: r.spendTxId, + index: r.index, + }]; + } + r.multipleSpendAttempts.push({ + txid: txid, + index: parseInt(index), + }); + } + else { + r.spendTxId = txid; + r.spendIndex = parseInt(index); + } + }; + + // This is not used now + TransactionDb.prototype.fromTxId = function(txid, cb) { + var self = this; var k = OUTS_PREFIX + txid; var ret=[]; var idx={}; @@ -93,6 +114,7 @@ function spec(b) { return cb(err); }) .on('end', function () { + var k = SPEND_PREFIX + txid; db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { @@ -102,15 +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); -/// TODO Handle multiple addresses here! - if (ret[j].spendTxId) { - // double spend! - assert(0); - } - else { - ret[j].spendTxId = k[4]; - ret[j].spendIndex = parseInt(k[5]); - } + self._addSpendInfo(ret[j], k[4], k[5]); }) .on('error', function (err) { return cb(err); @@ -135,7 +149,7 @@ function spec(b) { if (err || !addr || !valueSat ) { console.log('Could not get TXouts in %s,%d from %s ', i.txid, i.vout, info.txid); incompleteInputs = 1; - return c_in(); // error not scaled + return c_in(); // error not scalated } i.addr = addr; i.valueSat = valueSat; @@ -202,12 +216,37 @@ function spec(b) { o.isConfirmed = is; if (!o.spendTxId) return cb(); - self.isConfirmed(o.spendTxId, function(err,is) { - if (err) return cb(err); + if (o.multipleSpendAttempts) { - o.spendIsConfirmed = is; - return cb(); - }); + var isConfirmed = 0; + var txid, index; + async.each(o.multipleSpendAttempts, + function (oi) { + self.isConfirmed(oi.spendTxId, function(err,is) { + if (err) return cb(err); + isConfirmed = 1; + txid = oi.spendTxId; + index = oi.index; + return cb(); + }); + }, + function (err) { + // write the spended TXid into main register + if (isConfirmed) { + o.spendTxId = txid; + o.index = index; + o.spendIsConfirmed = 1; + } + return cb(err); + }); + } + else { + self.isConfirmed(o.spendTxId, function(err,is) { + if (err) return cb(err); + o.spendIsConfirmed = is; + return cb(); + }); + } }); }; @@ -238,16 +277,7 @@ function spec(b) { db.createReadStream({start: k, end: k + '~'}) .on('data', function (data) { var k = data.key.split('-'); - var v = data.value; - if (o.spendTxId) { - // double spend! - assert(0); - } - else { - o.spendTxId = k[4]; - o.spendIndex = parseInt(k[5]); - o.spendTs = parseInt(v); - } + self._addSpendInfo(o, k[4], k[5]); }) .on('error', function (err) { return e_c(err);