From 0bf989425ad3109ef770571e96f4ac989c745acd Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 9 Jan 2014 11:44:52 -0300 Subject: [PATCH 1/2] bitcoind diff --- etc/bitcoind/bitcoin.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/etc/bitcoind/bitcoin.conf b/etc/bitcoind/bitcoin.conf index 062c09e..879bede 100644 --- a/etc/bitcoind/bitcoin.conf +++ b/etc/bitcoind/bitcoin.conf @@ -6,7 +6,8 @@ testnet=3 txindex=1 # Allow connections outsite localhost? -# rpcallowip=192.168.0.* +rpcallowip=192.168.1.* +rpcallowip='192.168.1.*' From 35d5be894fb39e8b43d41a773410c80205d33844 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 9 Jan 2014 17:30:29 -0300 Subject: [PATCH 2/2] more information added to TX API: values and IN addresses. Test updated --- app/controllers/transactions.js | 13 +++- app/models/Block.js | 1 + app/models/Transaction.js | 108 +++++++++++++++++++++++++++++--- config/env/development.js | 3 +- config/routes.js | 3 + package.json | 1 + test/model/block.js | 8 ++- test/model/transaction.js | 9 ++- 8 files changed, 127 insertions(+), 19 deletions(-) diff --git a/app/controllers/transactions.js b/app/controllers/transactions.js index 6a4cffd..caa66f1 100644 --- a/app/controllers/transactions.js +++ b/app/controllers/transactions.js @@ -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); + } }; diff --git a/app/models/Block.js b/app/models/Block.js index a226c34..7374943 100644 --- a/app/models/Block.js +++ b/app/models/Block.js @@ -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); } ); }); diff --git a/app/models/Transaction.js b/app/models/Transaction.js index fb8cd86..8d26c70 100644 --- a/app/models/Transaction.js +++ b/app/models/Transaction.js @@ -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); + }); }); }; diff --git a/config/env/development.js b/config/env/development.js index 6836a43..e51b30f 100755 --- a/config/env/development.js +++ b/config/env/development.js @@ -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', } diff --git a/config/routes.js b/config/routes.js index fd522bd..f24ac7d 100644 --- a/config/routes.js +++ b/config/routes.js @@ -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'); diff --git a/package.json b/package.json index 1dd908e..33f323d 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "async": "*", "classtool": "*", "commander": "*", + "bignum": "*", "express": "~3.4.7", "jade": "~1.0.2", "mongoose": "~3.8.3", diff --git a/test/model/block.js b/test/model/block.js index 6a2b5f0..7fa2a30 100644 --- a/test/model/block.js +++ b/test/model/block.js @@ -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(); }); }); diff --git a/test/model/transaction.js b/test/model/transaction.js index bef066f..fe3aef0 100644 --- a/test/model/transaction.js +++ b/test/model/transaction.js @@ -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(); }); });