diff --git a/lib/services/address/index.js b/lib/services/address/index.js index b19f73c5..1e26e5e3 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -16,21 +16,25 @@ var AddressService = function(options) { BaseService.call(this, options); this._tx = this.node.services.transaction; this._header = this.node.services.header; + this._block = this.node.services.block; this._timestamp = this.node.services.timestamp; this._network = this.node.network; this._db = this.node.services.db; + if (this._network === 'livenet') { this._network = 'main'; } if (this._network === 'regtest') { this._network = 'testnet'; } + }; inherits(AddressService, BaseService); AddressService.dependencies = [ 'db', + 'block', 'header', 'transaction', 'timestamp' @@ -236,7 +240,7 @@ AddressService.prototype.getAddressUnspentOutputs = function(address, options, c ts: value.timestamp, scriptPubKey: value.script.toString('hex'), amount: Unit.fromSatoshis(value.satoshis).toBTC(), - confirmations: self._header.getBestHeight() - value.height, + height: value.height, satoshis: value.satoshis, confirmationsFromCache: true }); @@ -343,7 +347,7 @@ AddressService.prototype._getAddressHistory = function(address, options, callbac } assert(tx.__height >- 0, 'tx must have a height'); - self._header.getHeaderHash(tx.__height, function(err, hash) { + self._header.getBlockHeader(tx.__height, function(err, hash) { if(err) { log.error(err); diff --git a/lib/services/block/index.js b/lib/services/block/index.js index a91e1ae1..fba77bfe 100644 --- a/lib/services/block/index.js +++ b/lib/services/block/index.js @@ -80,32 +80,48 @@ BlockService.prototype.getBlock = function(arg, callback) { BlockService.prototype.getBlockOverview = function(hash, callback) { - this._getBlock(hash, function(err, block) { + var self = this; + self._getBlock(hash, function(err, block) { if (err) { return callback(err); } - var header = block.toHeaders().toJSON(); + if (!block) { + return callback(); + } - var blockOverview = { - hash: block.rhash(), - version: block.version, - confirmations: null, - height: header.height, - chainWork: header.chainwork, - prevHash: header.prevBlock, - nextHash: null, - merkleRoot: block.merkleroot, - time: block.ts, - medianTime: null, - nonce: block.nonce, - bits: block.bits, - difficulty: null, - txids: null - }; + self._header.getBlockHeader(hash, function(err, header) { - callback(null, blockOverview); + if (err) { + return callback(err); + } + + var target = bcoin.mining.common.getTarget(header.bits); + var difficulty = bcoin.mining.common.getDifficulty(target); + var txids = block.txs.map(function(tx) { + return tx.txid(); + }); + + var blockOverview = { + hash: block.rhash(), + version: block.version, + confirmations: self.getTip().height - header.height + 1, + height: header.height, + chainWork: header.chainwork, + prevHash: header.prevHash, + nextHash: null, + merkleRoot: header.merkleRoot, + time: block.ts, + medianTime: null, + nonce: header.nonce, + bits: header.bits, + difficulty: difficulty, + txids: txids + }; + + callback(null, blockOverview); + }); }); }; diff --git a/lib/services/transaction/index.js b/lib/services/transaction/index.js index 739540ff..dcfa3c17 100644 --- a/lib/services/transaction/index.js +++ b/lib/services/transaction/index.js @@ -3,9 +3,7 @@ var BaseService = require('../../service'); var inherits = require('util').inherits; var Encoding = require('./encoding'); -var utils = require('../../utils'); var _ = require('lodash'); -var log = require('../../index').log; var async = require('async'); var assert = require('assert'); @@ -50,7 +48,7 @@ TransactionService.prototype.getDetailedTransaction = function(txid, options, ca return callback(); } - self._header.getHeaderHash(tx.__height, function(err, hash) { + self._header.getBlockHeader(tx.__height, function(err, hash) { if (err) { return callback(err); diff --git a/test/regtest/address.js b/test/regtest/address.js index 2c86363d..7f2a074e 100644 --- a/test/regtest/address.js +++ b/test/regtest/address.js @@ -362,10 +362,405 @@ describe('Address', function() { done(); }); + }); + request.write(''); + request.end(); + }); + + it('should get a utxo: /addr/:addr/utxo', function(done) { + + var request = http.request('http://localhost:53001/api/addr/' + rpc1Address + '/utxo', function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(data); + expect(data.length).equal(1); + expect(data[0].amount).equal(20); + expect(data[0].satoshis).equal(2000000000); + expect(data[0].confirmations).equal(6); + done(); + }); + }); request.write(''); request.end(); + + }); + + it('should get multi-address utxos: /addrs/:addrs/utxo', function(done) { + + var request = http.request('http://localhost:53001/api/addrs/' + rpc2Address + ',' + rpc1Address + '/utxo', function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(data); + expect(data.length).to.equal(1); + expect(data[0].amount).to.equal(20); + expect(data[0].satoshis).to.equal(2000000000); + done(); + }); + + }); + + request.write(''); + request.end(); + + }); + + it('should post a utxo: /addrs/:addrs/utxo', function(done) { + + var body = JSON.stringify({ + addrs: [ rpc1Address, rpc2Address ] + }); + + var httpOpts = { + hostname: 'localhost', + port: 53001, + path: '/api/addrs/utxo', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': body.length + } + }; + + var request = http.request(httpOpts, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(data); + expect(data.length).to.equal(1); + expect(data[0].amount).to.equal(20); + expect(data[0].satoshis).to.equal(2000000000); + done(); + }); + + }); + + request.write(body); + request.end(); + + }); + + it('should get txs for a set of addresses: /addrs/:addrs/txs', function(done) { + + var httpOpts = { + hostname: 'localhost', + port: 53001, + path: '/api/addrs/' + rpc1Address + ',' + rpc2Address + '/txs', + method: 'GET' + }; + + var request = http.request(httpOpts, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(resData); + expect(data.items.length).to.equal(3); + expect(data.from).to.equal(0); + expect(data.to).to.equal(3); + done(); + }); + + }); + + request.write(''); + request.end(); + + }); + + it('should post txs for a set of addresses: /addrs/txs', function(done) { + + var body = JSON.stringify({ + addrs: [ rpc1Address, rpc2Address ] + }); + + var httpOpts = { + hostname: 'localhost', + port: 53001, + path: '/api/addrs/txs', + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } + }; + + var request = http.request(httpOpts, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(resData); + expect(data.items.length).to.equal(3); + expect(data.from).to.equal(0); + expect(data.to).to.equal(3); + done(); + }); + + }); + + request.write(body); + request.end(); + + }); + + it('should get totalReceived for an address: /addr/:addr/totalReceived', function(done) { + + var httpOpts = { + hostname: 'localhost', + port: 53001, + path: '/api/addr/' + rpc1Address + '/totalReceived', + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }; + + var request = http.request(httpOpts, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + + if (error) { + return; + } + + var data = JSON.parse(resData); + expect(data).to.equal(2000000000); + done(); + }); + + }); + + request.write(''); + request.end(); + + }); + + it('should get totalSent for an address: /addr/:addr/totalSent', function(done) { + + var httpOpts = { + hostname: 'localhost', + port: 53001, + path: '/api/addr/' + rpc1Address + '/totalSent', + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }; + + var request = http.request(httpOpts, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + expect(data).to.equal(0); + done(); + }); + + }); + + request.write(''); + request.end(); + + }); + + it('should get unconfirmedBalance for an address: /addr/:addr/unconfirmedBalance', function(done) { + + var httpOpts = { + hostname: 'localhost', + port: 53001, + path: '/api/addr/' + rpc1Address + '/unconfirmedBalance', + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }; + + var request = http.request(httpOpts, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + expect(data).to.equal(0); + done(); + }); + + }); + + request.write(''); + request.end(); + }); }); diff --git a/test/regtest/block.js b/test/regtest/block.js new file mode 100644 index 00000000..74e9f69d --- /dev/null +++ b/test/regtest/block.js @@ -0,0 +1,502 @@ +'use strict'; + +var expect = require('chai').expect; +var spawn = require('child_process').spawn; +var path = require('path'); +var rimraf = require('rimraf'); +var mkdirp = require('mkdirp'); +var fs = require('fs'); +var async = require('async'); +var RPC = require('bitcoind-rpc'); +var http = require('http'); + +var rpc1Address; +var rpc2Address; +var tx1; +var tx2; +var block; + +var rpcConfig = { + protocol: 'http', + user: 'local', + pass: 'localtest', + host: '127.0.0.1', + port: 58332, + rejectUnauthorized: false +}; + +var rpc1 = new RPC(rpcConfig); +rpcConfig.port++; +var rpc2 = new RPC(rpcConfig); +var debug = true; +var bitcoreDataDir = '/tmp/bitcore'; +var bitcoinDataDirs = ['/tmp/bitcoin1', '/tmp/bitcoin2']; + +var bitcoin = { + args: { + datadir: null, + listen: 1, + regtest: 1, + server: 1, + rpcuser: 'local', + rpcpassword: 'localtest', + //printtoconsole: 1 + rpcport: 58332, + }, + datadir: null, + exec: 'bitcoind', //if this isn't on your PATH, then provide the absolute path, e.g. /usr/local/bin/bitcoind + processes: [] +}; + +var bitcore = { + configFile: { + file: bitcoreDataDir + '/bitcore-node.json', + conf: { + network: 'regtest', + port: 53001, + datadir: bitcoreDataDir, + services: [ + 'p2p', + 'db', + 'header', + 'block', + 'address', + 'transaction', + 'mempool', + 'web', + 'insight-api', + 'fee', + 'timestamp' + ], + servicesConfig: { + 'p2p': { + 'peers': [ + { 'ip': { 'v4': '127.0.0.1' }, port: 18444 } + ] + }, + 'insight-api': { + 'routePrefix': 'api' + } + } + } + }, + httpOpts: { + protocol: 'http:', + hostname: 'localhost', + port: 53001, + }, + opts: { cwd: bitcoreDataDir }, + datadir: bitcoreDataDir, + exec: path.resolve(__dirname, '../../bin/bitcore-node'), + args: ['start'], + process: null +}; + +var startBitcoind = function(count, callback) { + + var listenCount = 0; + console.log('starting ' + count + ' bitcoind\'s'); + async.timesSeries(count, function(n, next) { + + var datadir = bitcoinDataDirs.shift(); + + bitcoin.datadir = datadir; + bitcoin.args.datadir = datadir; + + if (listenCount++ > 0) { + bitcoin.args.listen = 0; + bitcoin.args.rpcport++; + bitcoin.args.connect = '127.0.0.1'; + } + + rimraf(datadir, function(err) { + + if(err) { + return next(err); + } + + mkdirp(datadir, function(err) { + + if(err) { + return next(err); + } + + var args = bitcoin.args; + var argList = Object.keys(args).map(function(key) { + return '-' + key + '=' + args[key]; + }); + + var bitcoinProcess = spawn(bitcoin.exec, argList, bitcoin.opts); + bitcoin.processes.push(bitcoinProcess); + + bitcoinProcess.stdout.on('data', function(data) { + + if (debug) { + process.stdout.write(data.toString()); + } + + }); + + bitcoinProcess.stderr.on('data', function(data) { + + if (debug) { + process.stderr.write(data.toString()); + } + + }); + + next(); + + }); + + }); + }, function(err) { + + if (err) { + return callback(err); + } + + var pids = bitcoin.processes.map(function(process) { + return process.pid; + }); + + console.log(count + ' bitcoind\'s started at pid(s): ' + pids); + callback(); + }); +}; + + +var shutdownBitcoind = function(callback) { + bitcoin.processes.forEach(function(process) { + process.kill(); + }); + callback(); +}; + +var shutdownBitcore = function(callback) { + if (bitcore.process) { + bitcore.process.kill(); + } + callback(); +}; + + +var buildInitialChain = function(callback) { + async.waterfall([ + function(next) { + console.log('checking to see if bitcoind\'s are connected to each other.'); + rpc1.getinfo(function(err, res) { + if (err || res.result.connections !== 1) { + next(err || new Error('bitcoind\'s not connected to each other.')); + } + next(); + }); + }, + function(next) { + console.log('generating 101 blocks'); + rpc1.generate(101, next); + }, + function(res, next) { + console.log('getting new address from rpc2'); + rpc2.getNewAddress(function(err, res) { + if (err) { + return next(err); + } + rpc2Address = res.result; + console.log(rpc2Address); + next(null, rpc2Address); + }); + }, + function(addr, next) { + rpc1.sendToAddress(rpc2Address, 25, next); + }, + function(res, next) { + tx1 = res.result; + console.log('TXID: ' + res.result); + console.log('generating 7 blocks'); + rpc1.generate(7, next); + }, + function(res, next) { + block = res.result[res.result.length - 1]; + rpc2.getBalance(function(err, res) { + console.log(res); + next(); + }); + }, + function(next) { + console.log('getting new address from rpc1'); + rpc1.getNewAddress(function(err, res) { + if (err) { + return next(err); + } + rpc1Address = res.result; + next(null, rpc1Address); + }); + }, + function(addr, next) { + rpc2.sendToAddress(rpc1Address, 20, next); + }, + function(res, next) { + tx2 = res.result; + console.log('sending from rpc2Address TXID: ', res); + console.log('generating 6 blocks'); + rpc2.generate(6, next); + } + ], function(err) { + + if (err) { + return callback(err); + } + rpc1.getInfo(function(err, res) { + console.log(res); + callback(); + }); + }); + +}; + +var startBitcore = function(callback) { + + rimraf(bitcoreDataDir, function(err) { + + if(err) { + return callback(err); + } + + mkdirp(bitcoreDataDir, function(err) { + + if(err) { + return callback(err); + } + + fs.writeFileSync(bitcore.configFile.file, JSON.stringify(bitcore.configFile.conf)); + + var args = bitcore.args; + bitcore.process = spawn(bitcore.exec, args, bitcore.opts); + + bitcore.process.stdout.on('data', function(data) { + + if (debug) { + process.stdout.write(data.toString()); + } + + }); + bitcore.process.stderr.on('data', function(data) { + + if (debug) { + process.stderr.write(data.toString()); + } + + }); + + callback(); + }); + + }); + + +}; + +describe('Block', function() { + + this.timeout(60000); + + before(function(done) { + + async.series([ + function(next) { + startBitcoind(2, next); + }, + function(next) { + setTimeout(function() { + buildInitialChain(next); + }, 8000); + }, + function(next) { + setTimeout(function() { + startBitcore(next); + }, 6000); + } + ], function(err) { + if (err) { + return done(err); + } + setTimeout(done, 2000); + }); + + }); + + after(function(done) { + shutdownBitcoind(function() { + shutdownBitcore(done); + }); + }); + + it('should get blocks: /blocks', function(done) { + + var request = http.request('http://localhost:53001/api/blocks', function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + + if (error) { + return; + } + + return done('Error from bitcore-node webserver: ' + res.statusCode); + + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + expect(data.length).to.equal(114); + done(); + }); + + }); + request.write(''); + request.end(); + }); + + it('should get a block: /block/:hash', function(done) { + + var request = http.request('http://localhost:53001/api/block/' + block, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + + if (error) { + return; + } + + return done('Error from bitcore-node webserver: ' + res.statusCode); + + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + expect(data.hash).to.equal(block); + done(); + }); + + }); + request.write(''); + request.end(); + }); + + it('should get a block-index: /block-index/:height', function(done) { + + var request = http.request('http://localhost:53001/api/block-index/' + '108', function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + + if (error) { + return; + } + + return done('Error from bitcore-node webserver: ' + res.statusCode); + + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(resData); + expect(data.blockHash).to.equal(block); + done(); + }); + + }); + + request.write(''); + request.end(); + }); + + it('should get a raw block: /rawblock/:hash', function(done) { + + var request = http.request('http://localhost:53001/api/rawblock/' + block, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + + if (error) { + return; + } + + return done('Error from bitcore-node webserver: ' + res.statusCode); + + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(resData); + expect(data.rawblock).to.not.be.null; + done(); + }); + + }); + + request.write(''); + request.end(); + }); +}); + + + + diff --git a/test/regtest/transaction.js b/test/regtest/transaction.js new file mode 100644 index 00000000..b185012c --- /dev/null +++ b/test/regtest/transaction.js @@ -0,0 +1,450 @@ +'use strict'; + +var expect = require('chai').expect; +var spawn = require('child_process').spawn; +var path = require('path'); +var rimraf = require('rimraf'); +var mkdirp = require('mkdirp'); +var fs = require('fs'); +var async = require('async'); +var RPC = require('bitcoind-rpc'); +var http = require('http'); + +var rpc1Address; +var rpc2Address; +var tx1; +var tx2; +var block; + +var rpcConfig = { + protocol: 'http', + user: 'local', + pass: 'localtest', + host: '127.0.0.1', + port: 58332, + rejectUnauthorized: false +}; + +var rpc1 = new RPC(rpcConfig); +rpcConfig.port++; +var rpc2 = new RPC(rpcConfig); +var debug = true; +var bitcoreDataDir = '/tmp/bitcore'; +var bitcoinDataDirs = ['/tmp/bitcoin1', '/tmp/bitcoin2']; + +var bitcoin = { + args: { + datadir: null, + listen: 1, + regtest: 1, + server: 1, + rpcuser: 'local', + rpcpassword: 'localtest', + //printtoconsole: 1 + rpcport: 58332, + }, + datadir: null, + exec: 'bitcoind', //if this isn't on your PATH, then provide the absolute path, e.g. /usr/local/bin/bitcoind + processes: [] +}; + +var bitcore = { + configFile: { + file: bitcoreDataDir + '/bitcore-node.json', + conf: { + network: 'regtest', + port: 53001, + datadir: bitcoreDataDir, + services: [ + 'p2p', + 'db', + 'header', + 'block', + 'address', + 'transaction', + 'mempool', + 'web', + 'insight-api', + 'fee', + 'timestamp' + ], + servicesConfig: { + 'p2p': { + 'peers': [ + { 'ip': { 'v4': '127.0.0.1' }, port: 18444 } + ] + }, + 'insight-api': { + 'routePrefix': 'api' + } + } + } + }, + httpOpts: { + protocol: 'http:', + hostname: 'localhost', + port: 53001, + }, + opts: { cwd: bitcoreDataDir }, + datadir: bitcoreDataDir, + exec: path.resolve(__dirname, '../../bin/bitcore-node'), + args: ['start'], + process: null +}; + +var startBitcoind = function(count, callback) { + + var listenCount = 0; + console.log('starting ' + count + ' bitcoind\'s'); + async.timesSeries(count, function(n, next) { + + var datadir = bitcoinDataDirs.shift(); + + bitcoin.datadir = datadir; + bitcoin.args.datadir = datadir; + + if (listenCount++ > 0) { + bitcoin.args.listen = 0; + bitcoin.args.rpcport++; + bitcoin.args.connect = '127.0.0.1'; + } + + rimraf(datadir, function(err) { + + if(err) { + return next(err); + } + + mkdirp(datadir, function(err) { + + if(err) { + return next(err); + } + + var args = bitcoin.args; + var argList = Object.keys(args).map(function(key) { + return '-' + key + '=' + args[key]; + }); + + var bitcoinProcess = spawn(bitcoin.exec, argList, bitcoin.opts); + bitcoin.processes.push(bitcoinProcess); + + bitcoinProcess.stdout.on('data', function(data) { + + if (debug) { + process.stdout.write(data.toString()); + } + + }); + + bitcoinProcess.stderr.on('data', function(data) { + + if (debug) { + process.stderr.write(data.toString()); + } + + }); + + next(); + + }); + + }); + }, function(err) { + + if (err) { + return callback(err); + } + + var pids = bitcoin.processes.map(function(process) { + return process.pid; + }); + + console.log(count + ' bitcoind\'s started at pid(s): ' + pids); + callback(); + }); +}; + + +var shutdownBitcoind = function(callback) { + bitcoin.processes.forEach(function(process) { + process.kill(); + }); + callback(); +}; + +var shutdownBitcore = function(callback) { + if (bitcore.process) { + bitcore.process.kill(); + } + callback(); +}; + + +var buildInitialChain = function(callback) { + async.waterfall([ + function(next) { + console.log('checking to see if bitcoind\'s are connected to each other.'); + rpc1.getinfo(function(err, res) { + if (err || res.result.connections !== 1) { + next(err || new Error('bitcoind\'s not connected to each other.')); + } + next(); + }); + }, + function(next) { + console.log('generating 101 blocks'); + rpc1.generate(101, next); + }, + function(res, next) { + console.log('getting new address from rpc2'); + rpc2.getNewAddress(function(err, res) { + if (err) { + return next(err); + } + rpc2Address = res.result; + console.log(rpc2Address); + next(null, rpc2Address); + }); + }, + function(addr, next) { + rpc1.sendToAddress(rpc2Address, 25, next); + }, + function(res, next) { + tx1 = res.result; + console.log('TXID: ' + res.result); + console.log('generating 6 blocks'); + rpc1.generate(7, next); + }, + function(res, next) { + block = res.result[res.result.length - 1]; + rpc2.getBalance(function(err, res) { + console.log(res); + next(); + }); + }, + function(next) { + console.log('getting new address from rpc1'); + rpc1.getNewAddress(function(err, res) { + if (err) { + return next(err); + } + rpc1Address = res.result; + next(null, rpc1Address); + }); + }, + function(addr, next) { + rpc2.sendToAddress(rpc1Address, 20, next); + }, + function(res, next) { + tx2 = res.result; + console.log('sending from rpc2Address TXID: ', res); + console.log('generating 6 blocks'); + rpc2.generate(6, next); + } + ], function(err) { + + if (err) { + return callback(err); + } + rpc1.getInfo(function(err, res) { + console.log(res); + callback(); + }); + }); + +}; + +var startBitcore = function(callback) { + + rimraf(bitcoreDataDir, function(err) { + + if(err) { + return callback(err); + } + + mkdirp(bitcoreDataDir, function(err) { + + if(err) { + return callback(err); + } + + fs.writeFileSync(bitcore.configFile.file, JSON.stringify(bitcore.configFile.conf)); + + var args = bitcore.args; + bitcore.process = spawn(bitcore.exec, args, bitcore.opts); + + bitcore.process.stdout.on('data', function(data) { + + if (debug) { + process.stdout.write(data.toString()); + } + + }); + bitcore.process.stderr.on('data', function(data) { + + if (debug) { + process.stderr.write(data.toString()); + } + + }); + + callback(); + }); + + }); + + +}; + +describe('Transaction', function() { + + this.timeout(60000); + + before(function(done) { + + async.series([ + function(next) { + startBitcoind(2, next); + }, + function(next) { + setTimeout(function() { + buildInitialChain(next); + }, 8000); + }, + function(next) { + setTimeout(function() { + startBitcore(next); + }, 6000); + } + ], function(err) { + if (err) { + return done(err); + } + setTimeout(done, 2000); + }); + + }); + + after(function(done) { + shutdownBitcoind(function() { + shutdownBitcore(done); + }); + }); + + it('should get a transaction: /tx/:txid', function(done) { + + var request = http.request('http://localhost:53001/api/tx/' + tx1, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + expect(data.txid).to.equal(tx1); + done(); + }); + + }); + request.write(''); + request.end(); + }); + + it('should get transactions: /txs', function(done) { + + var request = http.request('http://localhost:53001/api/txs?block=' + block, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(resData); + expect(data.txs.length).to.equal(1); + done(); + }); + + }); + request.write(''); + request.end(); + }); + + it('should get a raw transactions: /rawtx/:txid', function(done) { + + var request = http.request('http://localhost:53001/api/rawtx/' + tx2, function(res) { + + var error; + if (res.statusCode !== 200 && res.statusCode !== 201) { + if (error) { + return; + } + return done('Error from bitcore-node webserver: ' + res.statusCode); + } + + var resError; + var resData = ''; + + res.on('error', function(e) { + resError = e; + }); + + res.on('data', function(data) { + resData += data; + }); + + res.on('end', function() { + if (error) { + return; + } + var data = JSON.parse(resData); + console.log(resData); + expect(data.rawtx).to.not.be.null; + done(); + }); + + }); + request.write(''); + request.end(); + }); +}); + + +