Merge pull request #385 from matiu/feature/unspent-outputs
add scriptpubkey to utxo
This commit is contained in:
commit
adfd363c76
|
@ -4,10 +4,14 @@ require('classtool');
|
|||
|
||||
|
||||
function spec() {
|
||||
var async = require('async');
|
||||
var BitcoreAddress = require('bitcore/Address').class();
|
||||
var BitcoreUtil = require('bitcore/util/util');
|
||||
var TransactionDb = require('../../lib/TransactionDb').class();
|
||||
var async = require('async');
|
||||
var BitcoreAddress = require('bitcore/Address').class();
|
||||
var BitcoreUtil = require('bitcore/util/util');
|
||||
var TransactionDb = require('../../lib/TransactionDb').class();
|
||||
var BitcoreTransaction = require('bitcore/Transaction').class();
|
||||
var Parser = require('bitcore/util/BinaryParser').class();
|
||||
var Buffer = require('buffer').Buffer;
|
||||
var CONCURRENCY = 5;
|
||||
|
||||
function Address(addrStr) {
|
||||
this.balanceSat = 0;
|
||||
|
@ -69,6 +73,14 @@ function spec() {
|
|||
|
||||
}
|
||||
|
||||
Address.prototype._getScriptPubKey = function(hex,n) {
|
||||
// ScriptPubKey is not provided by bitcoind RPC, so we parse it from tx hex.
|
||||
|
||||
var parser = new Parser(new Buffer(hex,'hex'));
|
||||
var tx = new BitcoreTransaction();
|
||||
tx.parse(parser);
|
||||
return (tx.outs[n].s.toString('hex'));
|
||||
};
|
||||
|
||||
Address.prototype.getUtxo = function(next) {
|
||||
var self = this;
|
||||
|
@ -80,22 +92,30 @@ function spec() {
|
|||
db.fromAddr(self.addrStr, function(err,txOut){
|
||||
if (err) return next(err);
|
||||
|
||||
txOut.forEach(function(txItem){
|
||||
// Complete utxo info
|
||||
async.eachLimit(txOut,CONCURRENCY,function (txItem, a_c) {
|
||||
db.fromIdInfoSimple(txItem.txid, function(err, info) {
|
||||
|
||||
// we are filtering out even unconfirmed spents!
|
||||
// add || !txItem.spentIsConfirmed
|
||||
if (!txItem.spentTxId) {
|
||||
ret.push({
|
||||
address: self.addrStr,
|
||||
txid: txItem.txid,
|
||||
vout: txItem.index,
|
||||
ts: txItem.ts,
|
||||
amount: txItem.value_sat / BitcoreUtil.COIN,
|
||||
confirmations: txItem.isConfirmed ? 1 : 0, // TODO => actually is 1+
|
||||
});
|
||||
}
|
||||
var scriptPubKey = self._getScriptPubKey(info.hex, txItem.index);
|
||||
|
||||
// we are filtering out even unconfirmed spents!
|
||||
// add || !txItem.spentIsConfirmed
|
||||
if (!txItem.spentTxId) {
|
||||
ret.push({
|
||||
address: self.addrStr,
|
||||
txid: txItem.txid,
|
||||
vout: txItem.index,
|
||||
ts: txItem.ts,
|
||||
scriptPubKey: scriptPubKey,
|
||||
amount: txItem.value_sat / BitcoreUtil.COIN,
|
||||
confirmations: txItem.isConfirmed ? info.confirmations : 0,
|
||||
});
|
||||
}
|
||||
return a_c(err);
|
||||
});
|
||||
}, function(err) {
|
||||
return next(err,ret);
|
||||
});
|
||||
return next(err,ret);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
13
lib/Rpc.js
13
lib/Rpc.js
|
@ -18,7 +18,7 @@ function spec(b) {
|
|||
Rpc._parseTxResult = function(info) {
|
||||
var b = new Buffer(info.hex,'hex');
|
||||
|
||||
// remove fields we dont need, to speed, and adapt the information
|
||||
// remove fields we dont need, to speed and adapt the information
|
||||
delete info['hex'];
|
||||
|
||||
// Inputs => add index + coinBase flag
|
||||
|
@ -53,17 +53,20 @@ function spec(b) {
|
|||
return e;
|
||||
};
|
||||
|
||||
Rpc.getTxInfo = function(txid, cb) {
|
||||
Rpc.getTxInfo = function(txid, doNotParse, cb) {
|
||||
var self = this;
|
||||
|
||||
bitcoreRpc.getRawTransaction(txid, 1, function(err, txInfo) {
|
||||
if (typeof doNotParse === 'function') {
|
||||
cb = doNotParse;
|
||||
doNotParse = false;
|
||||
}
|
||||
|
||||
bitcoreRpc.getRawTransaction(txid, 1, function(err, txInfo) {
|
||||
// Not found?
|
||||
if (err && err.code === -5) return cb();
|
||||
if (err) return cb(self.errMsg(err));
|
||||
|
||||
var info = self._parseTxResult(txInfo.result);
|
||||
|
||||
var info = doNotParse ? txInfo.result : self._parseTxResult(txInfo.result);
|
||||
return cb(null,info);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -267,13 +267,21 @@ isspent
|
|||
};
|
||||
|
||||
|
||||
// Simplified / faster Info version: No spent / outpoints info.
|
||||
TransactionDb.prototype.fromIdInfoSimple = function(txid, cb) {
|
||||
Rpc.getTxInfo(txid, true, function(err, info) {
|
||||
if (err) return cb(err);
|
||||
if (!info) return cb();
|
||||
return cb(err, info);
|
||||
});
|
||||
};
|
||||
|
||||
TransactionDb.prototype.fromIdWithInfo = function(txid, cb) {
|
||||
var self = this;
|
||||
|
||||
self._getInfo(txid, function(err, info) {
|
||||
if (err) return cb(err);
|
||||
if (!info) return cb();
|
||||
//console.log('[TransactionDb.js.278:info:]',info); //TODO
|
||||
return cb(err, {
|
||||
txid: txid,
|
||||
info: info
|
||||
|
@ -720,7 +728,6 @@ isspent
|
|||
return self.createFromArray(b.tx, b.hash, next);
|
||||
};
|
||||
|
||||
|
||||
return TransactionDb;
|
||||
}
|
||||
module.defineClass(spec);
|
||||
|
|
|
@ -8,7 +8,8 @@ var assert = require('assert'),
|
|||
fs = require('fs'),
|
||||
Address = require('../../app/models/Address').class(),
|
||||
TransactionDb = require('../../lib/TransactionDb').class(),
|
||||
addrValid = JSON.parse(fs.readFileSync('test/integration/addr.json'));
|
||||
addrValid = JSON.parse(fs.readFileSync('test/integration/addr.json')),
|
||||
utxoValid = JSON.parse(fs.readFileSync('test/integration/utxo.json'));
|
||||
|
||||
var txDb;
|
||||
describe('Address balances', function() {
|
||||
|
@ -52,3 +53,29 @@ describe('Address balances', function() {
|
|||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('Address utxo', function() {
|
||||
utxoValid.forEach(function(v) {
|
||||
if (v.disabled) {
|
||||
console.log(v.addr + ' => disabled in JSON');
|
||||
} else {
|
||||
it('Address utxo for: ' + v.addr, function(done) {
|
||||
this.timeout(50000);
|
||||
|
||||
var a = new Address(v.addr, txDb);
|
||||
a.getUtxo(function(err, utxo) {
|
||||
if (err) done(err);
|
||||
assert.equal(v.addr, a.addrStr);
|
||||
if (v.length) assert.equal(v.length, utxo.length, 'length: ' + utxo.length);
|
||||
if (v.tx0id) assert.equal(v.tx0id, utxo[0].txid, 'have tx: ' + utxo[0].txid);
|
||||
if (v.tx0scriptPubKey)
|
||||
assert.equal(v.tx0scriptPubKey, utxo[0].scriptPubKey, 'have tx: ' + utxo[0].scriptPubKey);
|
||||
if (v.tx0amount)
|
||||
assert.equal(v.tx0amount, utxo[0].amount, 'amount: ' + utxo[0].amount);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"addr": "muyg1K5WsHkfMVCkUXU2y7Xp5ZD6RGzCeH",
|
||||
"length": 1,
|
||||
"tx0id": "eeabc70063d3f266e190e8735bc4599c811d3a79d138da1364e88502069b029c",
|
||||
"tx0scriptPubKey": "76a9149e9f6515c70db535abdbbc983c7d8d1bff6c20cd88ac",
|
||||
"tx0amount": 0.38571339
|
||||
},
|
||||
{
|
||||
"addr": "mgKY35SXqxFpcKK3Dq9mW9919N7wYXvcFM",
|
||||
"length": 1,
|
||||
"tx0id": "91800d80bb4c69b238c9bfd94eb5155ab821e6b25cae5c79903d12853bbb4ed5",
|
||||
"tx0scriptPubKey": "76a91408cf4ceb2b7278043fcc7f545e6e6e73ef9a644f88ac",
|
||||
"tx0amount": 0.01979459
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue