addr tx orderer by TS. keep unconfirmed balance. fix times in txs
This commit is contained in:
parent
d561c191e7
commit
a35fcc776d
|
@ -43,5 +43,8 @@ module.exports.broadcastAddressTx = function(address, tx) {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.broadcastSyncInfo = function(historicSync) {
|
module.exports.broadcastSyncInfo = function(historicSync) {
|
||||||
if (ios) ios.sockets.in('sync').emit('status', historicSync);
|
|
||||||
|
if (ios) {
|
||||||
|
ios.sockets.in('sync').emit('status', historicSync);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,9 @@ function spec() {
|
||||||
this.balanceSat = 0;
|
this.balanceSat = 0;
|
||||||
this.totalReceivedSat = 0;
|
this.totalReceivedSat = 0;
|
||||||
this.totalSentSat = 0;
|
this.totalSentSat = 0;
|
||||||
|
|
||||||
|
this.unconfirmedBalanceSat = 0;
|
||||||
|
|
||||||
this.txApperances = 0;
|
this.txApperances = 0;
|
||||||
|
|
||||||
// TODO store only txids? +index? +all?
|
// TODO store only txids? +index? +all?
|
||||||
|
@ -51,12 +54,25 @@ function spec() {
|
||||||
},
|
},
|
||||||
enumerable: 1,
|
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) {
|
Address.prototype.update = function(next) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (!self.addrStr) return next();
|
if (!self.addrStr) return next();
|
||||||
|
|
||||||
|
var txs = [];
|
||||||
var db = new TransactionDb();
|
var db = new TransactionDb();
|
||||||
async.series([
|
async.series([
|
||||||
function (cb) {
|
function (cb) {
|
||||||
|
@ -64,27 +80,50 @@ function spec() {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
txOut.forEach(function(txItem){
|
txOut.forEach(function(txItem){
|
||||||
|
|
||||||
if (txItem.isConfirmed) {
|
|
||||||
var v = txItem.value_sat;
|
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) {
|
||||||
self.totalReceivedSat += v;
|
self.totalReceivedSat += v;
|
||||||
self.transactions.push(txItem.txid);
|
if (! txItem.spendTxId ) {
|
||||||
if (! txItem.spendTxId || !txItem.spendIsConfirmed) {
|
//unspend
|
||||||
|
self.balanceSat += v;
|
||||||
|
}
|
||||||
|
else if(!txItem.spendIsConfirmed) {
|
||||||
// unspent
|
// unspent
|
||||||
self.balanceSat += v;
|
self.balanceSat += v;
|
||||||
self.txApperances +=1;
|
self.unconfirmedBalanceSat -= v;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// spent
|
// spent
|
||||||
self.totalSentSat += v;
|
self.totalSentSat += v;
|
||||||
self.transactions.push(txItem.spendTxId);
|
|
||||||
self.txApperances +=2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
self.unconfirmedBalanceSat += v;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
], function (err) {
|
], 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);
|
return next(err);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -104,13 +104,14 @@ function spec() {
|
||||||
HistoricSync.prototype.showProgress = function() {
|
HistoricSync.prototype.showProgress = function() {
|
||||||
var self = this;
|
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) {
|
if (self.error) {
|
||||||
p('ERROR: ' + self.error);
|
p('ERROR: ' + self.error);
|
||||||
}
|
}
|
||||||
else {
|
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;
|
if (self.syncPercentage > 100) self.syncPercentage = 100;
|
||||||
|
|
||||||
p(util.format('status: [%d%%] skipped: %d ', self.syncPercentage, self.skippedBlocks));
|
p(util.format('status: [%d%%] skipped: %d ', self.syncPercentage, self.skippedBlocks));
|
||||||
|
@ -193,7 +194,6 @@ function spec() {
|
||||||
(blockEnd && blockEnd === blockHash)) {
|
(blockEnd && blockEnd === blockHash)) {
|
||||||
self.status = 'finished';
|
self.status = 'finished';
|
||||||
p('DONE. Found block: ', blockHash);
|
p('DONE. Found block: ', blockHash);
|
||||||
self.showProgress();
|
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +266,6 @@ function spec() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.showProgress();
|
self.showProgress();
|
||||||
|
|
||||||
self.getBlockFromFile(function(err, blockInfo) {
|
self.getBlockFromFile(function(err, blockInfo) {
|
||||||
if (err) {
|
if (err) {
|
||||||
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]',
|
self.setError(util.format('ERROR: @%s: %s [count: syncedBlocks: %d]',
|
||||||
|
@ -406,12 +405,14 @@ function spec() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
self.showProgress();
|
||||||
return next(err);
|
return next(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.type = 'from RPC calls';
|
self.type = 'from RPC calls';
|
||||||
self.getPrevNextBlock(start, end, scanOpts, function(err) {
|
self.getPrevNextBlock(start, end, scanOpts, function(err) {
|
||||||
|
self.showProgress();
|
||||||
return next(err);
|
return next(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.spendTxId) {
|
||||||
if (!r.multipleSpendAttempts) {
|
if (!r.multipleSpendAttempts) {
|
||||||
r.multipleSpendAttempts = [{
|
r.multipleSpendAttempts = [{
|
||||||
|
@ -85,6 +85,7 @@ function spec(b) {
|
||||||
else {
|
else {
|
||||||
r.spendTxId = txid;
|
r.spendTxId = txid;
|
||||||
r.spendIndex = parseInt(index);
|
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 +
|
assert(typeof j !== 'undefined','Spent could not be stored: tx ' + txid +
|
||||||
'spend in TX:' + k[2] + ',' + k[3]+ ' j:' + j);
|
'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) {
|
.on('error', function (err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
|
@ -144,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]);
|
self._addSpendInfo(info.vout[k[3]], k[4], k[5], data.value);
|
||||||
})
|
})
|
||||||
.on('error', function (err) {
|
.on('error', function (err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
|
@ -162,6 +163,7 @@ 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) {
|
||||||
|
@ -203,6 +205,8 @@ 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();
|
||||||
});
|
});
|
||||||
|
@ -264,7 +268,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]);
|
self._addSpendInfo(ret, k[4], k[5], data.value);
|
||||||
})
|
})
|
||||||
.on('error', function (error) {
|
.on('error', function (error) {
|
||||||
return cb(error);
|
return cb(error);
|
||||||
|
@ -336,7 +340,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]);
|
self._addSpendInfo(o, k[4], k[5], data.value);
|
||||||
})
|
})
|
||||||
.on('error', function (err) {
|
.on('error', function (err) {
|
||||||
return e_c(err);
|
return e_c(err);
|
||||||
|
@ -461,12 +465,20 @@ function spec(b) {
|
||||||
|
|
||||||
var addr = o.scriptPubKey.addresses[0];
|
var addr = o.scriptPubKey.addresses[0];
|
||||||
var sat = Math.round(o.value * util.COIN);
|
var sat = Math.round(o.value * util.COIN);
|
||||||
|
|
||||||
|
// existed?
|
||||||
|
db.get(OUTS_PREFIX + tx.txid + '-' + o.n, function (err,val) {
|
||||||
|
if (!val) {
|
||||||
db.batch()
|
db.batch()
|
||||||
.put( OUTS_PREFIX + tx.txid + '-' + o.n, addr + ':' + sat)
|
.put( OUTS_PREFIX + tx.txid + '-' + o.n, addr + ':' + sat)
|
||||||
.put( ADDR_PREFIX + addr + '-' + ts + '-' + tx.txid +
|
.put( ADDR_PREFIX + addr + '-' + ts + '-' + tx.txid +
|
||||||
'-' + o.n, sat)
|
'-' + o.n, sat)
|
||||||
.write(next_out);
|
.write(next_out);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return next_out();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//console.log ('WARN in TX: %s could not parse OUTPUT %d', tx.txid, o.n);
|
//console.log ('WARN in TX: %s could not parse OUTPUT %d', tx.txid, o.n);
|
||||||
|
|
|
@ -48,7 +48,10 @@ ScopedSocket.prototype.emit = function(event, data, callback) {
|
||||||
|
|
||||||
angular.module('insight.socket').factory('getSocket',
|
angular.module('insight.socket').factory('getSocket',
|
||||||
function($rootScope) {
|
function($rootScope) {
|
||||||
var socket = io.connect();
|
var socket = io.connect(null, {
|
||||||
|
'reconnect': true,
|
||||||
|
'reconnection delay': 500,
|
||||||
|
});
|
||||||
return function(scope) {
|
return function(scope) {
|
||||||
var scopedSocket = new ScopedSocket(socket, $rootScope);
|
var scopedSocket = new ScopedSocket(socket, $rootScope);
|
||||||
scope.$on('$routeChangeStart', function() {
|
scope.$on('$routeChangeStart', function() {
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
<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>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li>
|
<li>
|
||||||
<div class="status" data-ng-controller="StatusController">
|
<div class="status" data-ng-controller="StatusController">
|
||||||
<a href="#" data-ng-init="getSync()">
|
<div data-ng-init="getSync()" class="pull-left">
|
||||||
<span class="t text-danger" data-ng-show="sync.error" tooltip="{{sync.error}}" tooltip-placement="bottom">
|
<span class="t text-danger" data-ng-show="sync.error" tooltip="{{sync.error}}" tooltip-placement="bottom">
|
||||||
<span class="glyphicon glyphicon-warning-sign"></span>
|
<span class="glyphicon glyphicon-warning-sign"></span>
|
||||||
ERROR
|
ERROR
|
||||||
|
@ -33,8 +33,9 @@
|
||||||
<span class="glyphicon glyphicon-refresh icon-rotate"></span>
|
<span class="glyphicon glyphicon-refresh icon-rotate"></span>
|
||||||
{{sync.status}} {{sync.syncPercentage}}%
|
{{sync.status}} {{sync.syncPercentage}}%
|
||||||
</span>
|
</span>
|
||||||
<span class="t text-default" tooltip="Historic sync finished" tooltip-placement="bottom" data-ng-show="sync.status==='finished'"> On sync</span>
|
<span class="t text-default" tooltip="Historic sync finished" tooltip-placement="bottom" data-ng-show="sync.status==='finished'"> On sync </span>
|
||||||
</a> ·
|
</div>
|
||||||
|
·
|
||||||
<span data-ng-init="getStatus('Info')">
|
<span data-ng-init="getStatus('Info')">
|
||||||
<strong>Conn</strong> {{info.connections}}
|
<strong>Conn</strong> {{info.connections}}
|
||||||
</span> ·
|
</span> ·
|
||||||
|
|
|
@ -21,8 +21,15 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Received Time </strong></td>
|
<td><strong>Received Time </strong></td>
|
||||||
<td class="text-muted text-right">{{tx.time * 1000|date:'medium'}}</td>
|
<td data-ng-show="tx.firstSeenTs" class="text-muted text-right">{{tx.firstSeenTs * 1000|date:'medium'}}</td>
|
||||||
|
<td data-ng-show="!tx.firstSeenTs" class="text-muted text-right">N/A</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Mined Time </strong></td>
|
||||||
|
<td data-ng-show="tx.time" class="text-muted text-right">{{tx.time * 1000|date:'medium'}}</td>
|
||||||
|
<td data-ng-show="!tx.time" class="text-muted text-right">N/A</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div data-ng-include src="'/views/includes/currency.html'"></div>
|
<div data-ng-include src="'/views/includes/currency.html'"></div>
|
||||||
|
|
|
@ -6,7 +6,13 @@
|
||||||
<a class="txid" href="/tx/{{tx.txid}}">{{tx.txid}}</a>
|
<a class="txid" href="/tx/{{tx.txid}}">{{tx.txid}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-6 text-right" data-ng-show="tx.time">
|
|
||||||
|
<div class="col-xs-12 col-md-6 text-right" data-ng-show="tx.firstSeenTs">
|
||||||
|
first seen at
|
||||||
|
<time>{{tx.firstSeenTs * 1000 | date:'medium'}}</time>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-md-6 text-right" data-ng-show="tx.time && !tx.firstSeenTs">
|
||||||
|
mined at
|
||||||
<time>{{tx.time * 1000 | date:'medium'}}</time>
|
<time>{{tx.time * 1000 | date:'medium'}}</time>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29",
|
"addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29",
|
||||||
"txApperances": 2041,
|
"txApperances": 6049,
|
||||||
"balance": 1199.74393853,
|
"balance": 1199.74393853,
|
||||||
"totalReceived": 1199.74393853,
|
"totalReceived": 1199.74393853,
|
||||||
"totalSent": 0
|
"totalSent": 0
|
||||||
|
|
Loading…
Reference in New Issue