new levelDB roots. test updated

This commit is contained in:
Matias Alejo Garcia 2014-02-12 23:56:52 -03:00
parent 6cef1eaec3
commit 09e3e1d32f
9 changed files with 71 additions and 60 deletions

View File

@ -107,22 +107,18 @@ exports.list = function(req, res) {
res.status(500).send(err); res.status(500).send(err);
} }
else { else {
var blockshashList = [];
var limit = parseInt(req.query.limit || blocks.length); var limit = parseInt(req.query.limit || blocks.length);
if (blocks.length < limit) { if (blocks.length < limit) {
limit = blocks.length; limit = blocks.length;
} }
for(var i=0;i<limit;i++) { async.mapSeries(blocks,
blockshashList.push(blocks[i].hash); function(b, cb) {
} getBlock(b.hash, function(err, info) {
async.mapSeries(blockshashList,
function(hash, cb) {
getBlock(hash, function(err, info) {
return cb(err,{ return cb(err,{
height: info.height, height: info.height,
size: info.size, size: info.size,
hash: info.hash, hash: b.hash,
time: info.time, time: b.ts || info.time,
txlength: info.tx.length, txlength: info.tx.length,
}); });
}); });

View File

@ -16,7 +16,8 @@ function spec() {
this.unconfirmedBalanceSat = 0; this.unconfirmedBalanceSat = 0;
this.txApperances = 0; this.txApperances = 0;
this.unconfirmedTxApperances= 0;
// TODO store only txids? +index? +all? // TODO store only txids? +index? +all?
this.transactions = []; this.transactions = [];
@ -83,14 +84,13 @@ function spec() {
var v = txItem.value_sat; var v = txItem.value_sat;
txs.push({txid: txItem.txid, ts: txItem.ts}); txs.push({txid: txItem.txid, ts: txItem.ts});
self.txApperances += 1;
if (txItem.spendTxId) { if (txItem.spendTxId) {
txs.push({txid: txItem.spendTxId, ts: txItem.spendTs}); txs.push({txid: txItem.spendTxId, ts: txItem.spendTs});
self.txApperances += 1;
} }
if (txItem.isConfirmed) { if (txItem.isConfirmed) {
self.txApperances += 1;
self.totalReceivedSat += v; self.totalReceivedSat += v;
if (! txItem.spendTxId ) { if (! txItem.spendTxId ) {
//unspend //unspend
@ -100,14 +100,17 @@ function spec() {
// unspent // unspent
self.balanceSat += v; self.balanceSat += v;
self.unconfirmedBalanceSat -= v; self.unconfirmedBalanceSat -= v;
self.unconfirmedTxApperances += 1;
} }
else { else {
// spent // spent
self.totalSentSat += v; self.totalSentSat += v;
self.txApperances += 1;
} }
} }
else { else {
self.unconfirmedBalanceSat += v; self.unconfirmedBalanceSat += v;
self.unconfirmedTxApperances += 1;
} }
}); });
return cb(); return cb();

View File

@ -5,11 +5,11 @@ require('classtool');
function spec(b) { function spec(b) {
var TIMESTAMP_PREFIX = 'b-ts-'; // b-ts-<ts> => <hash> var TIMESTAMP_PREFIX = 'bts-'; // b-ts-<ts> => <hash>
var PREV_PREFIX = 'b-prev-'; // b-prev-<hash> => <prev_hash> var PREV_PREFIX = 'bpr-'; // b-prev-<hash> => <prev_hash>
var NEXT_PREFIX = 'b-next-'; // b-next-<hash> => <next_hash> var NEXT_PREFIX = 'bne-'; // b-next-<hash> => <next_hash>
var MAIN_PREFIX = 'b-main-'; // b-main-<hash> => 1/0 var MAIN_PREFIX = 'bma-'; // b-main-<hash> => 1/0
var TIP = 'b-tip-'; // last block on the chain var TIP = 'bti-'; // last block on the chain
/** /**
@ -125,14 +125,11 @@ function spec(b) {
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,val) { db.get(k, function (err,val) {
var ret; var ret = true;
if (err && err.notFound) { if (err && err.notFound) {
err = null; err = null;
ret = false; ret = false;
} }
if (typeof val !== 'undefined') {
ret = true;
}
return cb(err, ret); return cb(err, ret);
}); });
}; };
@ -170,8 +167,9 @@ function spec(b) {
fillCache: true fillCache: true
}) })
.on('data', function (data) { .on('data', function (data) {
var k = data.key.split('-');
list.push({ list.push({
ts: data.key.replace(TIMESTAMP_PREFIX, ''), ts: k[1],
hash: data.value, hash: data.value,
}); });
}) })

View File

@ -6,17 +6,17 @@ require('classtool');
function spec(b) { function spec(b) {
// blockHash -> txid mapping // blockHash -> txid mapping
var IN_BLK_PREFIX = 'tx-b-'; //tx-b-<txid>-<block> => 1/0 (connected or not) var IN_BLK_PREFIX = 'txb-'; //txb-<txid>-<block> => 1/0 (connected or not)
// Only for orphan blocks // Only for orphan blocks
var FROM_BLK_PREFIX = 'tx-'; //tx-<block>-<txid> => 1 var FROM_BLK_PREFIX = 'tx-'; //tx-<block>-<txid> => 1
// to show tx outs // to show tx outs
var OUTS_PREFIX = 'txouts-'; //txouts-<txid>-<n> => [addr, btc_sat] var OUTS_PREFIX = 'txo-'; //txo-<txid>-<n> => [addr, btc_sat]
var SPEND_PREFIX = 'txs-'; //txs-<txid(out)>-<n(out)>-<txid(in)>-<n(in)> = ts
// to sum up addr balance // to sum up addr balance (only outs, spends are gotten later)
var ADDR_PREFIX = 'txouts-addr-'; //txouts-addr-<addr>-<ts>-<txid>-<n> => + btc_sat var ADDR_PREFIX = 'txa-'; //txa-<addr>-<txid>-<n> => + btc_sat:ts
var SPEND_PREFIX = 'txouts-spend-';//txouts-spend-<txid(out)>-<n(out)>-<txid(in)>-<n(in)> = ts
// TODO: use bitcore networks module // TODO: use bitcore networks module
var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'; var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b';
@ -119,12 +119,12 @@ function spec(b) {
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({start: k, end: k + '~'})
.on('data', function (data) { .on('data', function (data) {
var k = data.key.split('-'); 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 + 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) { .on('error', function (err) {
return cb(err); return cb(err);
@ -145,7 +145,7 @@ function spec(b) {
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({start: k, end: k + '~'})
.on('data', function (data) { .on('data', function (data) {
var k = data.key.split('-'); 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) { .on('error', function (err) {
return cb(err); return cb(err);
@ -163,7 +163,6 @@ function spec(b) {
var valueIn = 0; var valueIn = 0;
var incompleteInputs = 0; var incompleteInputs = 0;
var ts;
async.eachLimit(info.vin, CONCURRENCY, function(i, c_in) { async.eachLimit(info.vin, CONCURRENCY, function(i, c_in) {
self.fromTxIdN(i.txid, i.vout, function(err, ret) { self.fromTxIdN(i.txid, i.vout, function(err, ret) {
@ -175,6 +174,7 @@ function spec(b) {
return c_in(); // error not scalated return c_in(); // error not scalated
} }
info.firstSeenTs = ret.spendTs;
i.unconfirmedInput = i.unconfirmedInput; i.unconfirmedInput = i.unconfirmedInput;
i.addr = ret.addr; i.addr = ret.addr;
i.valueSat = ret.valueSat; i.valueSat = ret.valueSat;
@ -205,8 +205,6 @@ function spec(b) {
i.doubleSpendTxID = null; i.doubleSpendTxID = null;
} }
info.firstSeenTs = i.spendTs;
valueIn += i.valueSat; valueIn += i.valueSat;
return c_in(); return c_in();
}); });
@ -268,7 +266,7 @@ function spec(b) {
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({start: k, end: k + '~'})
.on('data', function (data) { .on('data', function (data) {
var k = data.key.split('-'); 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) { .on('error', function (error) {
return cb(error); return cb(error);
@ -324,10 +322,10 @@ function spec(b) {
var k = data.key.split('-'); var k = data.key.split('-');
var v = data.value.split(':'); var v = data.value.split(':');
ret.push({ ret.push({
txid: k[2],
index: parseInt(k[3]),
value_sat: parseInt(v[0]), value_sat: parseInt(v[0]),
ts: parseInt(k[3]), ts: parseInt(v[1]),
txid: k[4],
index: parseInt(k[5]),
}); });
}) })
.on('error', function (err) { .on('error', function (err) {
@ -340,7 +338,7 @@ function spec(b) {
db.createReadStream({start: k, end: k + '~'}) db.createReadStream({start: k, end: k + '~'})
.on('data', function (data) { .on('data', function (data) {
var k = data.key.split('-'); 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) { .on('error', function (err) {
return e_c(err); return e_c(err);
@ -442,7 +440,8 @@ function spec(b) {
async.forEachLimit(tx.vin, CONCURRENCY, async.forEachLimit(tx.vin, CONCURRENCY,
function(i, next_out) { function(i, next_out) {
db.batch() 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); .write(next_out);
}, },
function (err) { function (err) {
@ -467,12 +466,12 @@ function spec(b) {
var sat = Math.round(o.value * util.COIN); var sat = Math.round(o.value * util.COIN);
// existed? // existed?
db.get(OUTS_PREFIX + tx.txid + '-' + o.n, function (err,val) { var k = OUTS_PREFIX + tx.txid + '-' + o.n;
if (!val) { db.get(k, function(err) {
if (err && err.notFound) {
db.batch() db.batch()
.put( OUTS_PREFIX + tx.txid + '-' + o.n, addr + ':' + sat) .put( k, addr + ':' + sat)
.put( ADDR_PREFIX + addr + '-' + ts + '-' + tx.txid + .put( ADDR_PREFIX + addr + '-' + tx.txid + '-' + o.n, sat+':'+ts)
'-' + o.n, sat)
.write(next_out); .write(next_out);
} }
else { else {

View File

@ -12,6 +12,7 @@
</div> </div>
<div class="m20v"> <div class="m20v">
<h4>Summary</h4> <h4>Summary</h4>
<h5>Confirmed</h5>
<table class="table"> <table class="table">
<tbody> <tbody>
<tr> <tr>
@ -26,17 +27,29 @@
<td class="small">Final Balance</td> <td class="small">Final Balance</td>
<td class="address ellipsis text-right">{{$root.currency.getConvertion(address.balance)}}</td> <td class="address ellipsis text-right">{{$root.currency.getConvertion(address.balance)}}</td>
</tr> </tr>
<tr>
<td class="small">Unconfirmed Tx Balance</td>
<td class="address ellipsis text-right">{{$root.currency.getConvertion(address.unconfirmedBalance)}}</td>
</tr>
<tr> <tr>
<td class="small">No. Transactions</td> <td class="small">No. Transactions</td>
<td class="address ellipsis text-right">{{address.txApperances}}</td> <td class="address ellipsis text-right">{{address.txApperances}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div data-ng-show="address.unconfirmedTxApperances">
<h5>Unconfirmed</h5>
<table class="table">
<tbody>
<tr>
<td class="small">Unconfirmed Txs Balance</td>
<td class="address ellipsis text-right">{{$root.currency.getConvertion(address.unconfirmedBalance)}}</td>
</tr>
<tr>
<td class="small">No. Transactions</td>
<td class="address ellipsis text-right">{{address.unconfirmedTxApperances}}</td>
</tr>
</tbody>
</table>
</div>
</div> <!-- END OF TRANSACTIONS TABLE --> </div> <!-- END OF TRANSACTIONS TABLE -->
<div data-ng-include src="'/views/includes/currency.html'"></div> <div data-ng-include src="'/views/includes/currency.html'"></div>
</div> <!-- END OF COL-MD-3 --> </div> <!-- END OF COL-MD-3 -->

View File

@ -30,6 +30,8 @@ describe('Address balances', function() {
a.update(function(err) { a.update(function(err) {
if (err) done(err); if (err) done(err);
assert.equal(v.addr, a.addrStr); assert.equal(v.addr, a.addrStr);
assert.equal(a.unconfirmedTxApperances ,0, 'unconfirmedTxApperances: 0');
assert.equal(a.unconfirmedBalanceSat ,0, 'unconfirmedBalanceSat: 0');
if (v.txApperances) if (v.txApperances)
assert.equal(v.txApperances, a.txApperances, 'txApperances: ' + a.txApperances); assert.equal(v.txApperances, a.txApperances, 'txApperances: ' + a.txApperances);
if (v.totalReceived) assert.equal(v.totalReceived, a.totalReceived, 'received: ' + a.totalReceived); if (v.totalReceived) assert.equal(v.totalReceived, a.totalReceived, 'received: ' + a.totalReceived);

View File

@ -43,10 +43,10 @@
}, },
{ {
"addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29", "addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29",
"txApperances": 6049,
"balance": 1199.74393853, "balance": 1199.74393853,
"totalReceived": 1199.74393853, "totalReceived": 1199.74393853,
"totalSent": 0 "totalSent": 0,
"txApperances": 5763
}, },
{ {
"addr": "mjRmkmYzvZN3cA3aBKJgYJ65epn3WCG84H", "addr": "mjRmkmYzvZN3cA3aBKJgYJ65epn3WCG84H",

View File

@ -6,8 +6,8 @@
{ {
"txid": "21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237", "txid": "21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237",
"toRm": [ "toRm": [
"txouts-spend-86a03cac7d87f596008c6d5a8d3fd8b88842932ea6f0337673eda16f6b472f7f-0", "txs-86a03cac7d87f596008c6d5a8d3fd8b88842932ea6f0337673eda16f6b472f7f-0",
"txouts-spend-bcd8da8ee847da377f8aaca92502c05e5f914c6a2452753146013b0e642a25a0-0" "txs-bcd8da8ee847da377f8aaca92502c05e5f914c6a2452753146013b0e642a25a0-0"
], ],
"items": [ "items": [
{ {
@ -25,7 +25,7 @@
{ {
"txid": "b633a6249d4a2bc123e7f8a151cae2d4afd17aa94840009f8697270c7818ceee", "txid": "b633a6249d4a2bc123e7f8a151cae2d4afd17aa94840009f8697270c7818ceee",
"toRm": [ "toRm": [
"txouts-spend-01621403689cb4a95699a3dbae029d7031c5667678ef14e2054793954fb27917-0" "txs-01621403689cb4a95699a3dbae029d7031c5667678ef14e2054793954fb27917-0"
], ],
"items": [ "items": [
{ {
@ -43,7 +43,7 @@
{ {
"txid": "ca2f42e44455b8a84434de139efea1fe2c7d71414a8939e0a20f518849085c3b", "txid": "ca2f42e44455b8a84434de139efea1fe2c7d71414a8939e0a20f518849085c3b",
"toRm": [ "toRm": [
"txouts-spend-2d7b680fb06e4d7eeb65ca49ac7522276586e0090b7fe662fc708129429c5e6a-0" "txs-2d7b680fb06e4d7eeb65ca49ac7522276586e0090b7fe662fc708129429c5e6a-0"
], ],
"items": [ "items": [
{ {

View File

@ -15,7 +15,7 @@ program
.option('-N --network [livenet]', 'Set bitcoin network [testnet]', 'testnet') .option('-N --network [livenet]', 'Set bitcoin network [testnet]', 'testnet')
.option('-D --destroy', 'Remove current DB (and start from there)', 0) .option('-D --destroy', 'Remove current DB (and start from there)', 0)
.option('-R --reverse', 'Sync backwards', 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('-F --fromfiles', 'Sync using bitcoind .dat block files (faster)', 0)
.option('-S --smart', 'genesis stored? uptoexisting = 1, fromFiles=1 [default]', true) .option('-S --smart', 'genesis stored? uptoexisting = 1, fromFiles=1 [default]', true)
.option('-v --verbose', 'Verbose 0/1', 0) .option('-v --verbose', 'Verbose 0/1', 0)