Merge pull request #220 from matiu/feature/handle-double-spends
Feature/handle double spends
This commit is contained in:
commit
3c317d700b
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@ -16,7 +16,7 @@ function spec(b) {
|
||||
|
||||
// to sum up addr balance
|
||||
var ADDR_PREFIX = 'txouts-addr-'; //txouts-addr-<addr>-<ts>-<txid>-<n> => + btc_sat
|
||||
var SPEND_PREFIX = 'txouts-spend-';//txouts-spend-<txid(out)>-<n(out)> => [txid(in),n(in),ts]
|
||||
var SPEND_PREFIX = 'txouts-spend-';//txouts-spend-<txid(out)>-<n(out)>-<txid(in)>-<n(in)> = ts
|
||||
|
||||
// TODO: use bitcore networks module
|
||||
var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b';
|
||||
@ -70,10 +70,33 @@ 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={};
|
||||
var i = 0;
|
||||
|
||||
// outs.
|
||||
db.createReadStream({start: k, end: k + '~'})
|
||||
@ -85,27 +108,23 @@ 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<l; i++) {
|
||||
if (ret[i].index === parseInt(k[3])) {
|
||||
ret[i].spendTxId = v[0];
|
||||
ret[i].spendIndex = parseInt(v[1]);
|
||||
set=1;
|
||||
}
|
||||
}
|
||||
assert(set,'Spent could not be stored: tx ' + txid +
|
||||
'spend in TX:' + k[2] + ',' + k[3]);
|
||||
var j = idx[parseInt(k[3])];
|
||||
|
||||
assert(typeof j !== 'undefined','Spent could not be stored: tx ' + txid +
|
||||
'spend in TX:' + k[2] + ',' + k[3]+ ' j:' + j);
|
||||
|
||||
self._addSpendInfo(ret[j], k[4], k[5]);
|
||||
})
|
||||
.on('error', function (err) {
|
||||
return cb(err);
|
||||
@ -130,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;
|
||||
@ -197,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();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -230,16 +274,17 @@ 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('-');
|
||||
self._addSpendInfo(o, k[4], k[5]);
|
||||
})
|
||||
.on('error', function (err) {
|
||||
return e_c(err);
|
||||
})
|
||||
.on('end', function (err) {
|
||||
return e_c(err);
|
||||
});
|
||||
},
|
||||
function() {
|
||||
async.each(ret, function(o, e_c){
|
||||
@ -335,8 +380,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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -45,7 +45,9 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td> <strong> Height </strong></td>
|
||||
<td class="text-right text-muted">{{block.height}}</td>
|
||||
<td class="text-right text-muted">{{block.height}}
|
||||
<span data-ng-show="block.isMainChain" class="text-success">(Mainchain)</span>
|
||||
<span data-ng-show="!block.isMainChain" class="text-danger"> <span class="glyphicon glyphicon-warning-sign"></span> (Orphaned)</span>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> <strong> Block Reward </strong></td>
|
||||
|
||||
@ -43,9 +43,9 @@
|
||||
},
|
||||
{
|
||||
"addr": "mzW2hdZN2um7WBvTDerdahKqRgj3md9C29",
|
||||
"txApperances": 6046,
|
||||
"balance": 1149.19744101,
|
||||
"totalReceived": 1149.19744101,
|
||||
"txApperances": 6047,
|
||||
"balance": 1199.74393851,
|
||||
"totalReceived": 1199.74393851,
|
||||
"totalSent": 0
|
||||
},
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user