show double spends, unconfirmed outpoints and incoherences
This commit is contained in:
parent
75dce7e926
commit
daa8327a5e
|
@ -7,7 +7,6 @@
|
|||
var Address = require('../models/Address'),
|
||||
common = require('./common');
|
||||
|
||||
|
||||
exports.address = function(req, res, next, addr) {
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -40,9 +40,6 @@ var walk = function(path) {
|
|||
|
||||
walk(models_path);
|
||||
|
||||
var syncOpts = {
|
||||
};
|
||||
|
||||
/**
|
||||
* p2pSync process
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
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();
|
||||
});
|
||||
},
|
||||
function (err) {
|
||||
// write the spended TXid into main register
|
||||
if (isConfirmed) {
|
||||
o.spendTxId = txid;
|
||||
o.index = index;
|
||||
if (err) return;
|
||||
if (is) {
|
||||
o.spendTxId = oi.spendTxId;
|
||||
o.index = oi.index;
|
||||
o.spendIsConfirmed = 1;
|
||||
}
|
||||
return cb(err);
|
||||
return e_c();
|
||||
});
|
||||
}, 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,14 +460,9 @@ 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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue