show double spends, unconfirmed outpoints and incoherences

This commit is contained in:
Matias Alejo Garcia 2014-02-11 13:31:33 -03:00
parent 75dce7e926
commit daa8327a5e
6 changed files with 126 additions and 49 deletions

View File

@ -7,7 +7,6 @@
var Address = require('../models/Address'),
common = require('./common');
exports.address = function(req, res, next, addr) {

34
dev-util/level-put.js Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env node
'use strict';
var config = require('../config/config'),
levelup = require('levelup');
var k = process.argv[2];
var v = process.argv[3];
var isBlock = process.argv[4] === '1';
var dbPath = config.leveldb + (isBlock ? '/blocks' : '/txs');
console.log('DB: ',dbPath); //TODO
var db = levelup(dbPath );
if (v) {
db.put(k,v,function(err) {
console.log('[PUT done]',err); //TODO
});
}
else {
db.del(k,function(err) {
console.log('[DEL done]',err); //TODO
});
}

View File

@ -40,9 +40,6 @@ var walk = function(path) {
walk(models_path);
var syncOpts = {
};
/**
* p2pSync process
*/

View File

@ -51,7 +51,6 @@ function spec(b) {
};
// TransactionDb.prototype.fromTxIdOne = function(txid, cb) { TODO
TransactionDb.prototype.has = function(txid, cb) {
var k = OUTS_PREFIX + txid;
@ -142,18 +141,46 @@ function spec(b) {
var valueIn = 0;
var incompleteInputs = 0;
async.eachLimit(info.vin, CONCURRENCY, function(i, c_in) {
self.fromTxIdN(i.txid, i.vout, function(err, addr, valueSat) {
if (err || !addr || !valueSat ) {
self.fromTxIdN(i.txid, i.vout, function(err, ret) {
//console.log('[TransactionDb.js.154:ret:]',ret); //TODO
if (!ret || !ret.addr || !ret.valueSat ) {
console.log('Could not get TXouts in %s,%d from %s ', i.txid, i.vout, info.txid);
if (ret) i.unconfirmedInput = ret.unconfirmedInput;
incompleteInputs = 1;
return c_in(); // error not scalated
}
i.addr = addr;
i.valueSat = valueSat;
i.value = valueSat / util.COIN;
i.unconfirmedInput = i.unconfirmedInput;
i.addr = ret.addr;
i.valueSat = ret.valueSat;
i.value = ret.valueSat / util.COIN;
// Double spend?
if ( ret.multipleSpendAttempt ||
!ret.spendTxId ||
(ret.spendTxId && ret.spendTxId !== info.txid)
) {
if (ret.multipleSpendAttempts ) {
ret.multipleSpendAttempts.each(function(mul) {
if (mul.spendTxId !== info.txid) {
i.doubleSpendTxID = ret.spendTxId;
i.doubleSpendIndex = ret.spendIndex;
}
});
}
else if (!ret.spendTxId) {
i.dbError = 'Input spend not registered';
}
else {
i.doubleSpendTxID = ret.spendTxId;
i.doubleSpendIndex = ret.spendIndex;
}
}
else {
i.doubleSpendTxID = null;
}
valueIn += i.valueSat;
return c_in();
@ -195,15 +222,35 @@ function spec(b) {
};
TransactionDb.prototype.fromTxIdN = function(txid, n, cb) {
var self = this;
var k = OUTS_PREFIX + txid + '-' + n;
db.get(k, function (err,val) {
if (err && err.notFound) {
err = null;
console.log('[TransactionDb.js.230]'); //TODO
if (!val || (err && err.notFound) ) {
return cb(null, { unconfirmedInput: 1} );
}
var a = val?val.split(':'):[null,null];
return cb(err, a[0], parseInt(a[1]));
var a = val.split(':');
var ret = {
addr: a[0],
valueSat: parseInt(a[1]),
};
// Spend?
var k = SPEND_PREFIX + txid + '-' + n;
db.createReadStream({start: k, end: k + '~'})
.on('data', function (data) {
var k = data.key.split('-');
self._addSpendInfo(ret, k[4], k[5]);
})
.on('error', function (error) {
return cb(error);
})
.on('end', function () {
return cb(null,ret);
});
});
};
@ -218,27 +265,18 @@ function spec(b) {
if (o.multipleSpendAttempts) {
var isConfirmed = 0;
var txid, index;
async.each(o.multipleSpendAttempts,
function (oi) {
async.each(o.multipleSpendAttempts,
function (oi, e_c) {
self.isConfirmed(oi.spendTxId, function(err,is) {
if (err) return cb(err);
isConfirmed = 1;
txid = oi.spendTxId;
index = oi.index;
return cb();
if (err) return;
if (is) {
o.spendTxId = oi.spendTxId;
o.index = oi.index;
o.spendIsConfirmed = 1;
}
return e_c();
});
},
function (err) {
// write the spended TXid into main register
if (isConfirmed) {
o.spendTxId = txid;
o.index = index;
o.spendIsConfirmed = 1;
}
return cb(err);
});
}, cb);
}
else {
self.isConfirmed(o.spendTxId, function(err,is) {
@ -367,7 +405,6 @@ function spec(b) {
TransactionDb.prototype.add = function(tx, blockhash, cb) {
var self = this;
var addrs = [];
var is_new = true;
if (tx.hash) self.adaptTxObject(tx);
@ -423,13 +460,8 @@ function spec(b) {
},
function (err) {
if (err) {
if (err.message.match(/E11000/)) {
is_new = false;
}
else {
console.log('ERR at TX %s: %s', tx.txid, err);
return cb(err);
}
console.log('ERR at TX %s: %s', tx.txid, err);
return cb(err);
}
return p_c();
});
@ -439,7 +471,7 @@ function spec(b) {
return self.setConfirmation(tx.txid,blockhash, true, p_c);
},
], function(err) {
return cb(err, addrs, is_new);
return cb(err, addrs);
});
};

View File

@ -19,12 +19,9 @@ function($scope, $rootScope, $routeParams, $location, Global, Transaction, Trans
var tmp = {};
var u = 0;
// TODO multiple output address
//
for(var i=0; i < l; i++) {
var notAddr = false;
// non standard input
if (items[i].scriptSig && !items[i].addr) {
items[i].addr = 'Unparsed address [' + u++ + ']';
@ -56,6 +53,10 @@ function($scope, $rootScope, $routeParams, $location, Global, Transaction, Trans
tmp[addr].items = [];
}
tmp[addr].doubleSpendTxID = tmp[addr].doubleSpendTxID || items[i].doubleSpendTxID;
tmp[addr].doubleSpendIndex = tmp[addr].doubleSpendIndex || items[i].doubleSpendIndex;
tmp[addr].unconfirmedInput += items[i].unconfirmedInput;
tmp[addr].dbError = tmp[addr].dbError || items[i].dbError;
tmp[addr].valueSat += items[i].value * COIN;
tmp[addr].value = items[i].value;
tmp[addr].items.push(items[i]);

View File

@ -28,6 +28,11 @@
<span class="text-muted" title="Current Bitcoin Address" data-ng-show="vin.addr == $root.currentAddr">{{vin.addr}}</span>
<a href="/address/{{vin.addr}}" data-ng-show="!vin.notAddr && vin.addr != $root.currentAddr">{{vin.addr}}</a>
</div>
<div data-ng-show="vin.unconfirmedInput" class="text-danger"> <span class="glyphicon glyphicon-warning-sign"></span> (Input unconfirmed)</div>
<div data-ng-show="vin.dbError" class="text-danger"> <span class="glyphicon glyphicon-warning-sign"></span> Incoherence in levelDB detected, please resync</div>
<div data-ng-show="vin.doubleSpendTxID" class="text-danger"> <span class="glyphicon glyphicon-warning-sign"></span> Double spend attempt detected. From tx:
<a href="/tx/{{vin.doubleSpendTxID}}">{{vin.doubleSpendTxID}},{{vin.doubleSpendIndex}}</a>
</div>
</div>
</div>
<div data-ng-repeat="vin in tx.vin" data-ng-show="itemsExpanded">
@ -38,6 +43,12 @@
<span data-ng-show="vin.notAddr">{{vin.addr}}</span>
<a href="/address/{{vin.addr}}" data-ng-show="!vin.notAddr">{{vin.addr}}</a>
</div>
<div data-ng-show="vin.unconfirmedInput" class="text-danger"> <span class="glyphicon glyphicon-warning-sign"></span> (Input unconfirmed)</div>
<div data-ng-show="vin.dbError" class="text-danger"> <span class="glyphicon glyphicon-warning-sign"></span> Incoherence in levelDB detected, please resync</div>
<div data-ng-show="vin.doubleSpendTxID" class="text-danger"> <span class="glyphicon glyphicon-warning-sign"></span> Double spend attempt detected. From tx:
<a href="/tx/{{vin.doubleSpendTxID}}">{{vin.doubleSpendTxID}},{{vin.doubleSpendIndex}}</a>
</div>
</div>
<div class="col-md-12">
<div class="panel panel-default">
@ -68,6 +79,8 @@
<span class="text-muted" title="Current Bitcoin Address" data-ng-show="address == $root.currentAddr" data-ng-repeat="address in vout.addr.split(',')">{{vout.addr}}</span>
<a href="/address/{{address}}" data-ng-show="!vout.notAddr && address != $root.currentAddr" data-ng-repeat="address in vout.addr.split(',')">{{address}}</a>
</div>
</div>
</div>
<div data-ng-repeat="vout in tx.vout" data-ng-show="itemsExpanded">
@ -108,7 +121,8 @@
</div>
<div class="line-top row">
<div class="col-xs-4 col-md-6">
<span data-ng-show="!tx.isCoinBase" class="label label-default">Fees: {{$root.currency.getConvertion(tx.fees)}}</span>
<span data-ng-show="!tx.isCoinBase && tx.feeds" class="label label-default">Fees: {{$root.currency.getConvertion(tx.fees)}}</span>
<span data-ng-show="!tx.isCoinBase && !tx.feeds" class="label label-default">Fees: unknown yet</span>
</div>
<div class="col-xs-8 col-md-6 text-right">
<span data-ng-show="tx.confirmations" class="label label-success">{{tx.confirmations}} Confirmations</span>