Merge pull request #9 from matiu/feature/add-addr-and-values-to-tx-API

Feature/add addr and values to tx api -- It will be use in transaction page
This commit is contained in:
Gustavo Maximiliano Cortez 2014-01-09 12:34:11 -08:00
commit e754d12129
9 changed files with 129 additions and 20 deletions

View File

@ -16,7 +16,12 @@ var Transaction = require('../models/Transaction');
*/
exports.transaction = function(req, res, next, txid) {
Transaction.fromIdWithInfo(txid, function(err, tx) {
if (err) return next(err);
if (err) {
console.log(err);
res.status(404).send('Not found');
return next();
}
if (!tx) return next(new Error('Failed to load TX ' + txid));
req.transaction = tx.info;
next();
@ -25,9 +30,11 @@ exports.transaction = function(req, res, next, txid) {
/**
* Show block
*/
exports.show = function(req, res) {
res.jsonp(req.transaction);
if (req.transaction) {
res.jsonp(req.transaction);
}
};

View File

@ -57,6 +57,7 @@ BlockSchema.statics.fromHash = function(hash, cb) {
BlockSchema.statics.fromHashWithInfo = function(hash, cb) {
this.fromHash(hash, function(err, block) {
if (err) return cb(err);
if (!block) { return cb(new Error('Block not found')); }
block.getInfo(function(err) { return cb(err,block); } );
});

View File

@ -3,10 +3,15 @@
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
async = require('async'),
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
async = require('async'),
RpcClient = require('bitcore/RpcClient').class(),
Transaction = require('bitcore/Transaction').class(),
Address = require('bitcore/Address').class(),
networks = require('bitcore/networks'),
util = require('bitcore/util/util'),
bignum = require('BigNum'),
config = require('../../config/config');
@ -41,10 +46,15 @@ TransactionSchema.statics.fromId = function(txid, cb) {
};
TransactionSchema.statics.fromIdWithInfo = function(txid, cb) {
// TODO Should we go to mongoDB first? Now, no extra information is stored at mongo.
this.fromId(txid, function(err, tx) {
if (err) return cb(err);
tx.getInfo(function(err) { return cb(err,tx); } );
if (!tx) { return cb(new Error('TX not found')); }
tx.queryInfo(function(err) { return cb(err,tx); } );
});
};
@ -79,18 +89,98 @@ TransactionSchema.statics.createFromArray = function(txs, next) {
};
TransactionSchema.methods.fillInputValues = function (tx, next) {
TransactionSchema.methods.getInfo = function (next) {
if (! this.rpc) this.rpc = new RpcClient(config.bitcoind);
var that = this;
var rpc = new RpcClient(config.bitcoind);
async.each(tx.ins, function(i, cb) {
rpc.getRawTransaction(this.txid, 1, function(err, txInfo) {
var outHash = i.getOutpointHash();
var outIndex = i.getOutpointIndex();
var outHashBase64 = outHash.reverse().toString('hex');
var c=0;
that.rpc.getRawTransaction(outHashBase64, function(err, txdata) {
var txin = new Transaction();
var b = new Buffer(txdata.result,'hex');
txin.parse(b);
txin.outs.forEach( function(j) {
// console.log( c + ': ' + util.formatValue(j.v) );
if (c === outIndex) {
i.value = j.v;
}
c++;
});
return cb();
});
},
function(err) {
return next(err);
}
);
};
TransactionSchema.methods.queryInfo = function (next) {
var that = this;
var network = ( config.network === 'testnet') ? networks.testnet : networks.livenet ;
this.rpc = new RpcClient(config.bitcoind);
this.rpc.getRawTransaction(this.txid, 1, function(err, txInfo) {
if (err) return next(err);
that.info = txInfo.result;
//console.log("THAT", that);
return next(null, that.info);
// Transaction parsing
var b = new Buffer(txInfo.result.hex,'hex');
var tx = new Transaction();
tx.parse(b);
that.fillInputValues(tx, function(err) {
// Copy TX relevant values to .info
var c = 0;
var valueIn = bignum(0);
var valueOut = bignum(0);
tx.ins.forEach(function(i) {
that.info.vin[c].value = util.formatValue(i.value);
var n = util.valueToBigInt(i.value).toNumber();
valueIn = valueIn.add( n );
var scriptSig = i.getScript();
var pubKey = scriptSig.simpleInPubKey();
var pubKeyHash = util.sha256ripe160(pubKey);
var addr = new Address(network.addressPubkey, pubKeyHash);
var addrStr = addr.toString();
that.info.vin[c].addr = addrStr;
c++;
});
tx.outs.forEach( function(i) {
var n = util.valueToBigInt(i.v).toNumber();
valueOut = valueOut.add(n);
});
that.info.valueIn = valueIn / util.COIN;
that.info.valueOut = valueOut / util.COIN;
that.info.feeds = (valueIn - valueOut) / util.COIN;
that.info.size = b.length;
return next(err, that.info);
});
});
};

View File

@ -11,5 +11,6 @@ module.exports = {
protocol: 'http',
host: process.env.BITCOIND_HOST || '127.0.0.1',
port: process.env.BITCOIND_PORT || '8332',
}
},
network: 'testnet',
}

View File

@ -9,8 +9,11 @@ module.exports = function(app) {
//Block routes
var blocks = require('../app/controllers/blocks');
app.get('/api/blocks', blocks.list);
app.get('/api/block/:blockHash', blocks.show);
app.param('blockHash', blocks.block);
app.get('/last_blocks', blocks.last_blocks);
var transactions = require('../app/controllers/transactions');

View File

@ -6,7 +6,8 @@ testnet=3
txindex=1
# Allow connections outsite localhost?
# rpcallowip=192.168.0.*
rpcallowip=192.168.1.*
rpcallowip='192.168.1.*'

View File

@ -38,6 +38,7 @@
"async": "*",
"classtool": "*",
"commander": "*",
"bignum": "*",
"express": "~3.4.7",
"jade": "~1.0.2",
"mongoose": "~3.8.3",

View File

@ -3,7 +3,7 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var TESTING_BLOCK = '0000000000b6288775bbd326bedf324ca8717a15191da58391535408205aada4';
var TESTING_BLOCK = '000000000185678d3d7ecc9962c96418174431f93fe20bf216d5565272423f74';
var
mongoose= require('mongoose'),
@ -14,7 +14,7 @@ var
mongoose.connection.on('error', function(err) { console.log(err); });
describe('Block getInfo', function(){
describe('Block fromHashWithInfo', function(){
before(function(done) {
mongoose.connect(config.db);
@ -27,7 +27,9 @@ describe('Block getInfo', function(){
});
it('should poll block\'s info from mongoose', function(done) {
console.log('asdasd');
var block2 = Block.fromHashWithInfo(TESTING_BLOCK, function(err, b2) {
console.log('333');
if (err) done(err);
assert.equal(b2.hash, TESTING_BLOCK);
@ -39,7 +41,7 @@ describe('Block getInfo', function(){
var block2 = Block.fromHashWithInfo(TESTING_BLOCK, function(err, b2) {
if (err) done(err);
assert.equal(b2.info.hash, TESTING_BLOCK);
assert.equal(b2.info.chainwork, '00000000000000000000000000000000000000000000000000446af21d50acd3');
assert.equal(b2.info.chainwork, '000000000000000000000000000000000000000000000000001b6dc969ffe847');
done();
});
});

View File

@ -3,7 +3,7 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var TESTING_TX = '9f4648538a8fd773029139f7e67cee51586bced78d7ff0388d10cb71096f2289';
var TESTING_TX = '21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237';
var
mongoose= require('mongoose'),
@ -14,7 +14,7 @@ var
mongoose.connection.on('error', function(err) { console.log(err); });
describe('Transaction getInfo', function(){
describe('Transaction fromIdWithInfo', function(){
before(function(done) {
mongoose.connect(config.db);
@ -38,7 +38,10 @@ describe('Transaction getInfo', function(){
Transaction.fromIdWithInfo(TESTING_TX, function(err, tx) {
if (err) done(err);
assert.equal(tx.info.txid, TESTING_TX);
assert.equal(tx.info.blockhash, '000000007af2a08af7ce4934167dc2afd7a2e6bfd31472332db02a6f38cb7b4d');
assert.equal(tx.info.blockhash, '000000000185678d3d7ecc9962c96418174431f93fe20bf216d5565272423f74');
assert.equal(tx.info.valueOut, 1.66174);
assert.equal(tx.info.feeds, 0.0005 );
assert.equal(tx.info.size, 226 );
done();
});
});