From c42b8d9d9103c155019ac339d72d147f1fbbce76 Mon Sep 17 00:00:00 2001 From: Joel Kaartinen Date: Tue, 29 Mar 2016 12:16:14 +0300 Subject: [PATCH 01/57] Optimize block list page to not parse all transactions from a block when the only data that is interesting is number of transactions. Fixes 100% CPU while building block list. --- lib/blocks.js | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 11806bd..d919d68 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -135,16 +135,34 @@ BlockController.prototype.list = function(req, res) { async.mapSeries( hashes, function(hash, next) { - self.node.getBlock(hash, function(err, block) { + self.node.services.bitcoind.getBlock(hash, function(err, blockBuffer) { if(err) { return next(err); } + var br = new bitcore.encoding.BufferReader(blockBuffer); + // take a shortcut to get number of transactions and the blocksize. + // Also reads the coinbase transaction and only that. + // Old code parsed all transactions in every block _and_ then encoded + // them all back together to get the binary size of the block. + // FIXME: This code might still read the whole block. Fixing that + // would require changes in bitcore-node. + var header = bitcore.BlockHeader.fromBufferReader(br); + var info = {}; + var txlength = br.readVarintNum(); + info.transactions = [bitcore.Transaction().fromBufferReader(br)]; - var info = self.node.services.bitcoind.getBlockIndex(hash); - block.__height = info.height; + var index = self.node.services.bitcoind.getBlockIndex(hash); + var block = { + height: index.height, + size: blockBuffer.length, + hash: hash, + time: header.time, + txlength: txlength, + poolInfo: self.getPoolInfo(info) + }; - if(moreTs > block.header.timestamp) { - moreTs = block.header.timestamp; + if(moreTs > header.timestamp) { + moreTs = header.timestamp; } return next(null, block); @@ -156,20 +174,11 @@ BlockController.prototype.list = function(req, res) { } blocks.sort(function(a, b) { - return b.__height - a.__height; + return b.height - a.height; }); var data = { - blocks: blocks.map(function(block) { - return { - height: block.__height, - size: block.toBuffer().length, - hash: block.hash, - time: block.header.time, - txlength: block.transactions.length, - poolInfo: self.getPoolInfo(block) - }; - }), + blocks: blocks, length: blocks.length, pagination: { next: next, From e4f585ad151ccabc5b0eb3058df2932558ab1d62 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 17 Mar 2016 12:18:03 -0400 Subject: [PATCH 02/57] general: updated controllers for new api from bitcoind --- lib/blocks.js | 52 ++++++++++--------- lib/index.js | 2 +- lib/status.js | 122 ++++++++++++++++++++++++++++---------------- lib/transactions.js | 59 +++++++++++---------- 4 files changed, 139 insertions(+), 96 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index d919d68..08cb148 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -37,11 +37,14 @@ BlockController.prototype.block = function(req, res, next, hash) { return common.handleErrors(err, res); } - var info = self.node.services.bitcoind.getBlockIndex(hash); - info.isMainChain = self.node.services.bitcoind.isMainChain(hash); + self.node.services.bitcoind.getBlockHeader(hash, function(err, info) { + if (err) { + return common.handleErrors(err, res); + } + req.block = self.transformBlock(block, info); + next(); + }); - req.block = self.transformBlock(block, info); - next(); }); }; @@ -52,7 +55,7 @@ BlockController.prototype.transformBlock = function(block, info) { }); return { hash: block.hash, - confirmations: this.node.services.db.tip.__height - info.height + 1, + confirmations: this.node.services.bitcoind.height - info.height + 1, size: block.toBuffer().length, height: info.height, version: blockObj.header.version, @@ -62,11 +65,11 @@ BlockController.prototype.transformBlock = function(block, info) { nonce: blockObj.header.nonce, bits: blockObj.header.bits.toString(16), difficulty: block.header.getDifficulty(), - chainwork: info.chainWork, + chainwork: info.chainwork, previousblockhash: blockObj.header.prevHash, - nextblockhash: this.node.services.bitcoind.getNextBlockHash(block.hash), + nextblockhash: info.nextblockhash, reward: this.getBlockReward(info.height) / 1e8, - isMainChain: info.isMainChain, + isMainChain: (info.confirmations !== -1), poolInfo: this.getPoolInfo(block) }; }; @@ -81,13 +84,13 @@ BlockController.prototype.show = function(req, res) { }; BlockController.prototype.blockIndex = function(req, res, next, height) { - var info = this.node.services.bitcoind.getBlockIndex(parseInt(height)); - if(!info) { - return common.handleErrors(null, res); - } - - res.jsonp({ - blockHash: info.hash + this.node.services.bitcoind.getBlockHeader(parseInt(height), function(err, info) { + if (err) { + return common.handleErrors(err, res); + } + res.jsonp({ + blockHash: info.hash + }); }); }; @@ -139,6 +142,7 @@ BlockController.prototype.list = function(req, res) { if(err) { return next(err); } + var br = new bitcore.encoding.BufferReader(blockBuffer); // take a shortcut to get number of transactions and the blocksize. // Also reads the coinbase transaction and only that. @@ -151,21 +155,23 @@ BlockController.prototype.list = function(req, res) { var txlength = br.readVarintNum(); info.transactions = [bitcore.Transaction().fromBufferReader(br)]; - var index = self.node.services.bitcoind.getBlockIndex(hash); - var block = { - height: index.height, + self.node.services.bitcoind.getBlockHeader(hash, function(err, blockHeader) { + + var block = { + height: blockHeader.height, size: blockBuffer.length, hash: hash, time: header.time, txlength: txlength, poolInfo: self.getPoolInfo(info) - }; + }; - if(moreTs > header.timestamp) { - moreTs = header.timestamp; - } + if(moreTs > header.timestamp) { + moreTs = header.timestamp; + } - return next(null, block); + return next(null, block); + }); }); }, function(err, blocks) { diff --git a/lib/index.js b/lib/index.js index e477b3f..25ee41a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -51,7 +51,7 @@ var InsightAPI = function(options) { this.txController = new TxController(this.node); }; -InsightAPI.dependencies = ['address', 'web']; +InsightAPI.dependencies = ['bitcoind', 'web']; inherits(InsightAPI, BaseService); diff --git a/lib/status.js b/lib/status.js index eac1f23..1f850a6 100644 --- a/lib/status.js +++ b/lib/status.js @@ -1,78 +1,112 @@ 'use strict'; +var common = require('./common'); + function StatusController(node) { this.node = node; } StatusController.prototype.show = function(req, res) { - var option = req.query.q; switch(option) { - case 'getDifficulty': - res.jsonp(this.getDifficulty()); - break; - case 'getLastBlockHash': - res.jsonp(this.getLastBlockHash()); - break; - case 'getBestBlockHash': - res.jsonp(this.getBestBlockHash()); - break; - case 'getInfo': - default: - res.jsonp(this.getInfo()); + case 'getDifficulty': + this.getDifficulty(function(err, result) { + if (err) { + return common.handleErrors(err, res); + } + res.jsonp(result); + }); + break; + case 'getLastBlockHash': + res.jsonp(this.getLastBlockHash()); + break; + case 'getBestBlockHash': + this.getBestBlockHash(function(err, result) { + if (err) { + return common.handleErrors(err, res); + } + res.jsonp(result); + }); + break; + case 'getInfo': + default: + this.getInfo(function(err, result) { + if (err) { + return common.handleErrors(err, res); + } + res.jsonp({ + info: result + }); + }); } }; -StatusController.prototype.getInfo = function() { - var info = this.node.services.bitcoind.getInfo(); - return { - info: info - }; +StatusController.prototype.getInfo = function(callback) { + this.node.services.bitcoind.getInfo(callback); }; StatusController.prototype.getLastBlockHash = function() { - var hash = this.node.services.db.tip.hash; + var hash = this.node.services.bitcoind.tiphash; return { syncTipHash: hash, lastblockhash: hash }; }; -StatusController.prototype.getBestBlockHash = function() { - var hash = this.node.services.bitcoind.getBestBlockHash(); - return { - bestblockhash: hash - }; +StatusController.prototype.getBestBlockHash = function(callback) { + this.node.services.bitcoind.getBestBlockHash(function(err, hash) { + if (err) { + return callback(err); + } + callback(null, { + bestblockhash: hash + }); + }); }; -StatusController.prototype.getDifficulty = function() { - var info = this.node.services.bitcoind.getInfo(); - return { - difficulty: info.difficulty - }; +StatusController.prototype.getDifficulty = function(callback) { + this.node.services.bitcoind.getInfo(function(err, info) { + if (err) { + return callback(err); + } + callback(null, { + difficulty: info.difficulty + }); + }); }; StatusController.prototype.sync = function(req, res) { + var self = this; var status = 'syncing'; - if(this.node.services.bitcoind.isSynced() && this.node.services.db.tip.__height === this.node.services.bitcoind.height) { - status = 'finished'; - } - // Not exactly the total blockchain height, - // but we will reach 100% when our db and bitcoind are both fully synced - var totalHeight = this.node.services.bitcoind.height / (this.node.services.bitcoind.syncPercentage() / 100); + this.node.services.bitcoind.isSynced(function(err, synced) { + if (err) { + return common.handleErrors(err, res); + } + if (synced) { + status = 'finished'; + } - var info = { - status: status, - blockChainHeight: this.node.services.bitcoind.height, - syncPercentage: Math.round(this.node.services.db.tip.__height / totalHeight * 100), - height: this.node.services.db.tip.__height, - error: null, - type: 'bitcore node' - }; + self.node.services.bitcoind.syncPercentage(function(err, percentage) { + if (err) { + return common.handleErrors(err, res); + } + var info = { + status: status, + blockChainHeight: self.node.services.bitcoind.height, + syncPercentage: Math.round(percentage), + height: self.node.services.bitcoind.height, + error: null, + type: 'bitcore node' + }; + + res.jsonp(info); + + }); + + }); - res.jsonp(info); }; // Hard coded to make insight ui happy, but not applicable diff --git a/lib/transactions.js b/lib/transactions.js index c471986..87bf352 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -31,7 +31,7 @@ TxController.prototype.transaction = function(req, res, next, txid) { return common.handleErrors(err, res); } - transaction.populateInputs(self.node.services.db, [], function(err) { + transaction.populateInputs(self.node.services.bitcoind, [], function(err) { if(err) { return res.send({ error: err.toString() @@ -58,7 +58,7 @@ TxController.prototype.transformTransaction = function(transaction, callback) { var confirmations = 0; if(transaction.__height >= 0) { - confirmations = this.node.services.db.tip.__height - transaction.__height + 1; + confirmations = this.node.services.bitcoind.height - transaction.__height + 1; } var transformed = { @@ -179,7 +179,7 @@ TxController.prototype.transformOutput = function(txid, output, index, callback) queryMempool: true }; - self.node.services.address.getInputForOutput( + self.node.services.bitcoind.getInputForOutput( txid, index, options, @@ -269,36 +269,39 @@ TxController.prototype.list = function(req, res) { return common.handleErrors(err, res); } - var blockInfo = self.node.services.bitcoind.getBlockIndex(block.hash); - var txs = block.transactions; - var totalTxs = txs.length; + self.node.services.bitcoind.getBlockHeader(block.hash, function(err, blockInfo) { + var txs = block.transactions; + var totalTxs = txs.length; - if(!_.isUndefined(page)) { - txs = txs.splice(page * pageLength, pageLength); - pagesTotal = Math.ceil(totalTxs / pageLength); - } - - async.mapSeries(txs, function(tx, next) { - tx.__blockHash = block.hash; - tx.__height = blockInfo.height; - tx.__timestamp = block.header.time; - - tx.populateInputs(self.node.services.db, [], function(err) { - if(err) { - return next(err); - } - self.transformTransaction(tx, next); - }); - }, function(err, transformed) { - if(err) { - return common.handleErrors(err, res); + if(!_.isUndefined(page)) { + txs = txs.splice(page * pageLength, pageLength); + pagesTotal = Math.ceil(totalTxs / pageLength); } - res.jsonp({ - pagesTotal: pagesTotal, - txs: transformed + async.mapSeries(txs, function(tx, next) { + tx.__blockHash = block.hash; + tx.__height = blockInfo.height; + tx.__timestamp = block.header.time; + + tx.populateInputs(self.node.services.bitcoind, [], function(err) { + if(err) { + return next(err); + } + self.transformTransaction(tx, next); + }); + }, function(err, transformed) { + if(err) { + return common.handleErrors(err, res); + } + + res.jsonp({ + pagesTotal: pagesTotal, + txs: transformed + }); }); + }); + }); } else if(address) { var options = { From 13efeec84b70354223eb5c6c0b8f775174012a9e Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 23 Mar 2016 10:47:56 -0400 Subject: [PATCH 03/57] blocks: fix for getBlockHashesByTimestamp --- lib/blocks.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 08cb148..6b95a74 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -39,10 +39,10 @@ BlockController.prototype.block = function(req, res, next, hash) { self.node.services.bitcoind.getBlockHeader(hash, function(err, info) { if (err) { - return common.handleErrors(err, res); + return common.handleErrors(err, res); } req.block = self.transformBlock(block, info); - next(); + next(); }); }); @@ -125,7 +125,7 @@ BlockController.prototype.list = function(req, res) { var more = false; var moreTs = lte; - self.node.services.db.getBlockHashesByTimestamp(lte, gte, function(err, hashes) { + self.node.services.bitcoind.getBlockHashesByTimestamp(lte, gte, function(err, hashes) { if(err) { return common.handleErrors(err, res); } From 3c355c30a9fee884a02672e077b27b1acd8de6b6 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 23 Mar 2016 12:57:26 -0400 Subject: [PATCH 04/57] blocks: added lru cache --- lib/addresses.js | 2 +- lib/blocks.js | 133 ++++++++++++++++++++++++++++++----------------- package.json | 1 + 3 files changed, 86 insertions(+), 50 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index 765faab..065375b 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -90,7 +90,7 @@ AddressController.prototype.checkAddrs = function(req, res, next) { } this.check(req, res, next, req.addrs); -} +}; AddressController.prototype.check = function(req, res, next, addresses) { if(!addresses.length || !addresses[0]) { diff --git a/lib/blocks.js b/lib/blocks.js index 6b95a74..96a7edf 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -5,11 +5,16 @@ var async = require('async'); var bitcore = require('bitcore-lib'); var pools = require('../pools.json'); var BN = bitcore.crypto.BN; +var LRU = require('lru-cache'); + function BlockController(node) { var self = this; this.node = node; + this.blockSummaryCache = LRU(1000000); + this.blockCache = LRU(1000); + this.poolStrings = {}; pools.forEach(function(pool) { pool.searchStrings.forEach(function(s) { @@ -29,23 +34,34 @@ var BLOCK_LIMIT = 200; BlockController.prototype.block = function(req, res, next, hash) { var self = this; - this.node.getBlock(hash, function(err, block) { - if(err && err.message === 'Block not found.') { - // TODO libbitcoind should pass an instance of errors.Block.NotFound - return common.handleErrors(null, res); - } else if(err) { - return common.handleErrors(err, res); - } + function finish(blockResult) { + blockResult.confirmations = self.node.services.bitcoind.height - blockResult.height + 1; + req.block = blockResult; + next(); + } - self.node.services.bitcoind.getBlockHeader(hash, function(err, info) { - if (err) { + var block = self.blockCache.get(hash); + + if (block) { + finish(block); + } else { + self.node.getBlock(hash, function(err, block) { + if(err && err.message === 'Block not found.') { + // TODO libbitcoind should pass an instance of errors.Block.NotFound + return common.handleErrors(null, res); + } else if(err) { return common.handleErrors(err, res); } - req.block = self.transformBlock(block, info); - next(); + self.node.services.bitcoind.getBlockHeader(hash, function(err, info) { + if (err) { + return common.handleErrors(err, res); + } + var blockResult = self.transformBlock(block, info); + self.blockCache.set(hash, blockResult); + finish(blockResult); + }); }); - - }); + } }; BlockController.prototype.transformBlock = function(block, info) { @@ -55,7 +71,6 @@ BlockController.prototype.transformBlock = function(block, info) { }); return { hash: block.hash, - confirmations: this.node.services.bitcoind.height - info.height + 1, size: block.toBuffer().length, height: info.height, version: blockObj.header.version, @@ -94,6 +109,58 @@ BlockController.prototype.blockIndex = function(req, res, next, height) { }); }; +BlockController.prototype._getBlockSummary = function(hash, moreTs, next) { + var self = this; + + function finish(result) { + if (moreTs > result.time) { + moreTs = result.time; + } + return next(null, result); + } + + var summaryCache = self.blockSummaryCache.get(hash); + + if (summaryCache) { + finish(summaryCache); + } else { + self.node.services.bitcoind.getRawBlock(hash, function(err, blockBuffer) { + if(err) { + return next(err); + } + + var br = new bitcore.encoding.BufferReader(blockBuffer); + // take a shortcut to get number of transactions and the blocksize. + // Also reads the coinbase transaction and only that. + // Old code parsed all transactions in every block _and_ then encoded + // them all back together to get the binary size of the block. + // FIXME: This code might still read the whole block. Fixing that + // would require changes in bitcore-node. + var header = bitcore.BlockHeader.fromBufferReader(br); + var info = {}; + var txlength = br.readVarintNum(); + info.transactions = [bitcore.Transaction().fromBufferReader(br)]; + + self.node.services.bitcoind.getBlockHeader(hash, function(err, blockHeader) { + + var block = { + height: blockHeader.height, + size: blockBuffer.length, + hash: hash, + time: header.time, + txlength: txlength, + poolInfo: self.getPoolInfo(info) + }; + + self.blockSummaryCache.set(hash, summary); + + finish(block); + }); + }); + + } +}; + // List blocks by date BlockController.prototype.list = function(req, res) { var self = this; @@ -130,6 +197,8 @@ BlockController.prototype.list = function(req, res) { return common.handleErrors(err, res); } + hashes.reverse(); + if(hashes.length > limit) { more = true; hashes = hashes.slice(0, limit); @@ -138,41 +207,7 @@ BlockController.prototype.list = function(req, res) { async.mapSeries( hashes, function(hash, next) { - self.node.services.bitcoind.getBlock(hash, function(err, blockBuffer) { - if(err) { - return next(err); - } - - var br = new bitcore.encoding.BufferReader(blockBuffer); - // take a shortcut to get number of transactions and the blocksize. - // Also reads the coinbase transaction and only that. - // Old code parsed all transactions in every block _and_ then encoded - // them all back together to get the binary size of the block. - // FIXME: This code might still read the whole block. Fixing that - // would require changes in bitcore-node. - var header = bitcore.BlockHeader.fromBufferReader(br); - var info = {}; - var txlength = br.readVarintNum(); - info.transactions = [bitcore.Transaction().fromBufferReader(br)]; - - self.node.services.bitcoind.getBlockHeader(hash, function(err, blockHeader) { - - var block = { - height: blockHeader.height, - size: blockBuffer.length, - hash: hash, - time: header.time, - txlength: txlength, - poolInfo: self.getPoolInfo(info) - }; - - if(moreTs > header.timestamp) { - moreTs = header.timestamp; - } - - return next(null, block); - }); - }); + self._getBlockSummary(hash, moreTs, next); }, function(err, blocks) { if(err) { diff --git a/package.json b/package.json index 869fd93..8eb0f77 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "bitcore-message": "^1.0.1", "body-parser": "^1.13.3", "lodash": "^2.4.1", + "lru-cache": "^4.0.1", "request": "^2.64.0" }, "devDependencies": { From 78870fc56eccd564b024dd2daa11489ba451115d Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 25 Mar 2016 16:51:47 -0400 Subject: [PATCH 05/57] fixed bug that was removing transactions from the cached block --- lib/transactions.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/transactions.js b/lib/transactions.js index 87bf352..dbcf5a1 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -270,12 +270,15 @@ TxController.prototype.list = function(req, res) { } self.node.services.bitcoind.getBlockHeader(block.hash, function(err, blockInfo) { - var txs = block.transactions; - var totalTxs = txs.length; + var totalTxs = block.transactions.length; + var txs; if(!_.isUndefined(page)) { - txs = txs.splice(page * pageLength, pageLength); + var start = page * pageLength; + txs = block.transactions.slice(start, start + pageLength); pagesTotal = Math.ceil(totalTxs / pageLength); + } else { + txs = block.transactions; } async.mapSeries(txs, function(tx, next) { From b18dc95755672275e7ab6dceb85d581f01449d2c Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 5 Apr 2016 10:32:34 -0400 Subject: [PATCH 06/57] address: update utxos --- lib/addresses.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index 065375b..7e82030 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -117,13 +117,12 @@ AddressController.prototype.check = function(req, res, next, addresses) { AddressController.prototype.utxo = function(req, res) { var self = this; - this.node.getUnspentOutputs(req.addr, true, function(err, utxos) { - if(err && err instanceof self.node.errors.NoOutputs) { - return res.jsonp([]); - } else if(err) { + this.node.getAddressUnspentOutputs(req.addr, {}, function(err, utxos) { + if(err) { return common.handleErrors(err, res); + } else if (!utxos.length) { + return res.jsonp([]); } - res.jsonp(utxos.map(self.transformUtxo.bind(self))); }); }; @@ -147,10 +146,12 @@ AddressController.prototype.transformUtxo = function(utxo) { address: utxo.address, txid: utxo.txid, vout: utxo.outputIndex, + height: utxo.height, ts: utxo.timestamp ? parseInt(utxo.timestamp) : Date.now(), scriptPubKey: utxo.script, amount: utxo.satoshis / 1e8, - confirmations: utxo.confirmations + satoshis: utxo.satoshis, + confirmations: this.node.services.bitcoind.height - utxo.height + 1 }; }; From de4a87e5f8c4085ff13bceb73c146dfd7d02b734 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 5 Apr 2016 14:51:38 -0400 Subject: [PATCH 07/57] index: update bitcoind tx event handler --- lib/index.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/index.js b/lib/index.js index 25ee41a..9354d50 100644 --- a/lib/index.js +++ b/lib/index.js @@ -181,14 +181,12 @@ InsightAPI.prototype.blockHandler = function(block, add, callback) { }); }; -InsightAPI.prototype.transactionHandler = function(txInfo) { - if(txInfo.mempool) { - var tx = Transaction().fromBuffer(txInfo.buffer); - tx = this.txController.transformInvTransaction(tx); +InsightAPI.prototype.transactionHandler = function(txBuffer) { + var tx = new Transaction().fromBuffer(txBuffer); + var result = this.txController.transformInvTransaction(tx); - for (var i = 0; i < this.subscriptions.inv.length; i++) { - this.subscriptions.inv[i].emit('tx', tx); - } + for (var i = 0; i < this.subscriptions.inv.length; i++) { + this.subscriptions.inv[i].emit('tx', result); } }; From 8280d7a628eb11f627e98ed851ea10cff9d2bf1f Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 7 Apr 2016 07:04:51 -0400 Subject: [PATCH 08/57] index: added response logging --- lib/index.js | 24 ++++++++++++++++++++++++ package.json | 1 + 2 files changed, 25 insertions(+) diff --git a/lib/index.js b/lib/index.js index 9354d50..fb061be 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,6 @@ 'use strict'; +var Writable = require('stream').Writable; var bodyParser = require('body-parser'); var BaseService = require('./service'); var inherits = require('util').inherits; @@ -10,6 +11,7 @@ var StatusController = require('./status'); var MessagesController = require('./messages'); var UtilsController = require('./utils'); var CurrencyController = require('./currency'); +var morgan = require('morgan'); var bitcore = require('bitcore-lib'); var _ = bitcore.deps._; var $ = bitcore.util.preconditions; @@ -85,8 +87,30 @@ InsightAPI.prototype.start = function(callback) { setImmediate(callback); }; +InsightAPI.prototype.createLogInfoStream = function() { + var self = this; + + function Log(options) { + Writable.call(this, options); + } + inherits(Log, Writable); + + Log.prototype._write = function (chunk, enc, callback) { + self.node.log.info(chunk.slice(0, chunk.length - 1)); // remove new line and pass to logger + callback(); + }; + var stream = new Log(); + + return stream; +}; + InsightAPI.prototype.setupRoutes = function(app) { + //Setup logging + var logFormat = ':remote-addr ":method :url" :status :res[content-length] :response-time ":user-agent" '; + var logStream = this.createLogInfoStream(); + app.use(morgan(logFormat, {stream: logStream})); + app.use(bodyParser.urlencoded({extended: true})); //Enable CORS diff --git a/package.json b/package.json index 8eb0f77..30ae085 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "body-parser": "^1.13.3", "lodash": "^2.4.1", "lru-cache": "^4.0.1", + "morgan": "^1.7.0", "request": "^2.64.0" }, "devDependencies": { From 0957f2301e3dbf3f8df1a7076ceb155487d4f5c5 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 7 Apr 2016 07:19:11 -0400 Subject: [PATCH 09/57] index: add compression to responses --- lib/index.js | 5 +++++ package.json | 1 + 2 files changed, 6 insertions(+) diff --git a/lib/index.js b/lib/index.js index fb061be..aed421a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,6 +2,7 @@ var Writable = require('stream').Writable; var bodyParser = require('body-parser'); +var compression = require('compression'); var BaseService = require('./service'); var inherits = require('util').inherits; var BlockController = require('./blocks'); @@ -111,6 +112,10 @@ InsightAPI.prototype.setupRoutes = function(app) { var logStream = this.createLogInfoStream(); app.use(morgan(logFormat, {stream: logStream})); + //Enable compression + app.use(compression()); + + //Enable urlencoded data app.use(bodyParser.urlencoded({extended: true})); //Enable CORS diff --git a/package.json b/package.json index 30ae085..52e60e7 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "bitcore-lib": "^0.13.7", "bitcore-message": "^1.0.1", "body-parser": "^1.13.3", + "compression": "^1.6.1", "lodash": "^2.4.1", "lru-cache": "^4.0.1", "morgan": "^1.7.0", From 491a5cb84699068eb9d390e489d7af1447a6564e Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 7 Apr 2016 08:01:49 -0400 Subject: [PATCH 10/57] index: start of rate limiter --- lib/index.js | 5 ++ lib/ratelimiter.js | 132 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 lib/ratelimiter.js diff --git a/lib/index.js b/lib/index.js index aed421a..468f7ea 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,6 +12,7 @@ var StatusController = require('./status'); var MessagesController = require('./messages'); var UtilsController = require('./utils'); var CurrencyController = require('./currency'); +var RateLimiter = require('./ratelimiter'); var morgan = require('morgan'); var bitcore = require('bitcore-lib'); var _ = bitcore.deps._; @@ -107,6 +108,10 @@ InsightAPI.prototype.createLogInfoStream = function() { InsightAPI.prototype.setupRoutes = function(app) { + //Enable rate limiter + var limiter = new RateLimiter({node: this.node}); + app.use(limiter.middleware()); + //Setup logging var logFormat = ':remote-addr ":method :url" :status :res[content-length] :response-time ":user-agent" '; var logStream = this.createLogInfoStream(); diff --git a/lib/ratelimiter.js b/lib/ratelimiter.js new file mode 100644 index 0000000..c4b2f66 --- /dev/null +++ b/lib/ratelimiter.js @@ -0,0 +1,132 @@ +'use strict'; + +var THREE_HOURS = 3* 60 * 60 * 1000; + +/** + * A rate limiter to be used as an express middleware. + * + * @param {Object} options + * @param {Number} options.limit - Number of requests for normal rate limiter + * @param {Number} options.every - Interval of the normal rate limiter + * @param {Array} options.whitelist - IP addresses that should have whitelist rate limiting + * @param {Array} options.blacklist - IP addresses that should be blacklist rate limiting + * @param {Number} options.whitelistLimit - Number of requests for whitelisted clients + * @param {Number} options.whitelistEvery - Interval for whitelisted clients + * @param {Number} options.blacklistLimit - Number of requests for blacklisted clients + * @param {Number} options.blacklistEvery - Interval for blacklisted clients + */ +function RateLimiter(options) { + if (!(this instanceof RateLimiter)) { + return new RateLimiter(options); + } + + if (!options){ + options = {}; + } + + this.node = options.node; + this.clients = {}; + this.whitelist = options.whitelist || []; + this.blacklist = options.blacklist || []; + + this.config = { + whitelist: { + totalRequests: options.whitelistLimit || 3 * 60 * 60 * 10, // 108,000 + every: options.whitelistEvery || THREE_HOURS + }, + blacklist: { + totalRequests: options.blacklistLimit || 0, + every: options.blacklistEvery || THREE_HOURS + }, + normal: { + totalRequests: options.limit || 3 * 60 * 60, // 10,800 + every: options.every || THREE_HOURS + } + }; + +} + +RateLimiter.prototype.middleware = function() { + var self = this; + return function(req, res, next) { + self._middleware(req, res, next); + }; +}; + +RateLimiter.prototype._middleware = function(req, res, next) { + + var name = this.getClientName(req); + var client = this.clients[name]; + + res.ratelimit = { + clients: this.clients, + exceeded: false + }; + + if (!client) { + client = this.addClient(name); + } + + res.setHeader('X-RateLimit-Limit', this.config[client.type].totalRequests); + res.setHeader('X-RateLimit-Remaining', this.config[client.type].totalRequests - client.visits); + + res.ratelimit.exceeded = this.exceeded(client); + res.ratelimit.client = client; + + if (!this.exceeded(client)) { + client.visits++; + next(); + } else { + this.node.log.warn('Rate limited:', client); + res.status(429).jsonp({ + status: 429, + error: 'Rate limit exceeded' + }); + } +}; + +RateLimiter.prototype.exceeded = function(client) { + if (this.config[client.type].totalRequests === -1) { + return false; + } else { + return client.visits > this.config[client.type].totalRequests; + } +}; + +RateLimiter.prototype.getClientType = function(name) { + if (this.whitelist.indexOf(name) > -1) { + return 'whitelist'; + } + if (this.blacklist.indexOf(name) > -1) { + return 'blacklist'; + } + return 'normal'; +}; + +RateLimiter.prototype.getClientName = function(req) { + var name = req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress; + return name; +}; + +RateLimiter.prototype.addClient = function(name) { + var self = this; + + var client = { + name: name, + type: this.getClientType(name), + visits: 1 + }; + + var resetTime = this.config[client.type].every; + + setTimeout(function() { + delete self.clients[name]; + }, resetTime).unref(); + + this.clients[name] = client; + + return client; + +}; + +module.exports = RateLimiter; From 9d78188f64847330edd119024a75828753aaaa5e Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 7 Apr 2016 08:35:37 -0400 Subject: [PATCH 11/57] index: add not found --- lib/index.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/index.js b/lib/index.js index 468f7ea..a5d82a1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -190,6 +190,15 @@ InsightAPI.prototype.setupRoutes = function(app) { }); app.get('/currency', currency.index.bind(currency)); + // Not Found + app.use(function(req, res) { + res.status(404).jsonp({ + status: 404, + url: req.originalUrl, + error: 'Not found' + }); + }); + }; InsightAPI.prototype.getPublishEvents = function() { From 19c5b617d1b098bc7d00c30b91e8e88614202c93 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 11 Apr 2016 10:39:46 -0400 Subject: [PATCH 12/57] block: only cache block summary with height if confirmed >= 6 - update api with changes in bitcore node - add block event --- lib/blocks.js | 19 ++++++++++++++----- lib/index.js | 15 +++++---------- lib/transactions.js | 4 ++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 96a7edf..3463748 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -13,6 +13,7 @@ function BlockController(node) { this.node = node; this.blockSummaryCache = LRU(1000000); + this.blockSummaryCacheConfirmations = 6; this.blockCache = LRU(1000); this.poolStrings = {}; @@ -125,11 +126,12 @@ BlockController.prototype._getBlockSummary = function(hash, moreTs, next) { finish(summaryCache); } else { self.node.services.bitcoind.getRawBlock(hash, function(err, blockBuffer) { - if(err) { + if (err) { return next(err); } var br = new bitcore.encoding.BufferReader(blockBuffer); + // take a shortcut to get number of transactions and the blocksize. // Also reads the coinbase transaction and only that. // Old code parsed all transactions in every block _and_ then encoded @@ -142,9 +144,13 @@ BlockController.prototype._getBlockSummary = function(hash, moreTs, next) { info.transactions = [bitcore.Transaction().fromBufferReader(br)]; self.node.services.bitcoind.getBlockHeader(hash, function(err, blockHeader) { + if (err) { + return next(err); + } + var height = blockHeader.height; - var block = { - height: blockHeader.height, + var summary = { + height: height, size: blockBuffer.length, hash: hash, time: header.time, @@ -152,9 +158,12 @@ BlockController.prototype._getBlockSummary = function(hash, moreTs, next) { poolInfo: self.getPoolInfo(info) }; - self.blockSummaryCache.set(hash, summary); + var confirmations = self.node.services.bitcoind.height - height + 1; + if (confirmations >= self.blockSummaryCacheConfirmations) { + self.blockSummaryCache.set(hash, summary); + } - finish(block); + finish(summary); }); }); diff --git a/lib/index.js b/lib/index.js index a5d82a1..5a915e4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -84,8 +84,8 @@ InsightAPI.prototype.getRoutePrefix = function() { }; InsightAPI.prototype.start = function(callback) { - this.node.services.bitcoind.on('tx', this.transactionHandler.bind(this)); - + this.node.services.bitcoind.on('tx', this.transactionEventHandler.bind(this)); + this.node.services.bitcoind.on('block', this.blockEventHandler.bind(this)); setImmediate(callback); }; @@ -213,18 +213,13 @@ InsightAPI.prototype.getPublishEvents = function() { ]; }; -InsightAPI.prototype.blockHandler = function(block, add, callback) { +InsightAPI.prototype.blockEventHandler = function(hashBuffer) { // Notify inv subscribers for (var i = 0; i < this.subscriptions.inv.length; i++) { - this.subscriptions.inv[i].emit('block', block.hash); + this.subscriptions.inv[i].emit('block', hashBuffer.toString('hex')); } - - setImmediate(function() { - callback(null, []); - }); }; - -InsightAPI.prototype.transactionHandler = function(txBuffer) { +InsightAPI.prototype.transactionEventHandler = function(txBuffer) { var tx = new Transaction().fromBuffer(txBuffer); var result = this.txController.transformInvTransaction(tx); diff --git a/lib/transactions.js b/lib/transactions.js index dbcf5a1..657caa6 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -24,7 +24,7 @@ TxController.prototype.show = function(req, res) { TxController.prototype.transaction = function(req, res, next, txid) { var self = this; - this.node.getTransactionWithBlockInfo(txid, true, function(err, transaction) { + this.node.getTransactionWithBlockInfo(txid, function(err, transaction) { if (err && err instanceof self.node.errors.Transaction.NotFound) { return common.handleErrors(null, res); } else if(err) { @@ -231,7 +231,7 @@ TxController.prototype.transformInvTransaction = function(transaction) { TxController.prototype.rawTransaction = function(req, res, next, txid) { var self = this; - this.node.getTransaction(txid, true, function(err, transaction) { + this.node.getTransaction(txid, function(err, transaction) { if (err && err instanceof self.node.errors.Transaction.NotFound) { return common.handleErrors(null, res); } else if(err) { From 7ded22fb2cfc855d74fbcaca7dbc73f93c610ee1 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 11 Apr 2016 15:40:55 -0400 Subject: [PATCH 13/57] block: add raw block endpoint --- lib/blocks.js | 26 ++++++++++++++++++++++++++ lib/index.js | 3 +++ 2 files changed, 29 insertions(+) diff --git a/lib/blocks.js b/lib/blocks.js index 3463748..572d54a 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -65,6 +65,26 @@ BlockController.prototype.block = function(req, res, next, hash) { } }; +/** + * Find rawblock by hash and height... + */ +BlockController.prototype.rawBlock = function(req, res, next, blockArg) { + var self = this; + + self.node.getRawBlock(blockArg, function(err, blockBuffer) { + if(err && err.code === -5) { + return common.handleErrors(null, res); + } else if(err) { + return common.handleErrors(err, res); + } + req.rawBlock = { + rawblock: blockBuffer.toString('hex') + }; + next(); + }); + +}; + BlockController.prototype.transformBlock = function(block, info) { var blockObj = block.toObject(); var transactionIds = blockObj.transactions.map(function(tx) { @@ -99,6 +119,12 @@ BlockController.prototype.show = function(req, res) { } }; +BlockController.prototype.showRaw = function(req, res) { + if (req.rawBlock) { + res.jsonp(req.rawBlock); + } +}; + BlockController.prototype.blockIndex = function(req, res, next, height) { this.node.services.bitcoind.getBlockHeader(parseInt(height), function(err, info) { if (err) { diff --git a/lib/index.js b/lib/index.js index 5a915e4..0e02cfa 100644 --- a/lib/index.js +++ b/lib/index.js @@ -138,6 +138,9 @@ InsightAPI.prototype.setupRoutes = function(app) { app.get('/block/:blockHash', this.cacheLong(), blocks.show.bind(blocks)); app.param('blockHash', blocks.block.bind(blocks)); + app.get('/rawblock/:blockArg', this.cacheLong(), blocks.showRaw.bind(blocks)); + app.param('blockArg', blocks.rawBlock.bind(blocks)); + app.get('/block-index/:height', this.cacheLong(), blocks.blockIndex.bind(blocks)); app.param('height', blocks.blockIndex.bind(blocks)); From 38bbbc07dcd07ffc93a0e63f0b8a025cf97c0f57 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 12 Apr 2016 15:01:27 -0400 Subject: [PATCH 14/57] transaction: spent info api updates --- lib/transactions.js | 105 ++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 68 deletions(-) diff --git a/lib/transactions.js b/lib/transactions.js index 657caa6..505695a 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -79,45 +79,29 @@ TxController.prototype.transformTransaction = function(transaction, callback) { transformed.vin = txObj.inputs.map(this.transformInput.bind(this)); } - async.map( - Object.keys(txObj.outputs), - function(outputIndex, next) { - outputIndex = parseInt(outputIndex); - var output = txObj.outputs[outputIndex]; - self.transformOutput(txid, output, outputIndex, next); - }, - function(err, vout) { - if (err) { - return callback(err); - } + transformed.vout = transaction.outputs.map(this.transformOutput.bind(this)); - transformed.vout = vout; + transformed.blockhash = transaction.__blockHash; + transformed.blockheight = transaction.__height; + transformed.confirmations = confirmations; + var time = transaction.__timestamp ? transaction.__timestamp : Math.round(Date.now() / 1000); + transformed.time = time; + if (transformed.confirmations) { + transformed.blocktime = transformed.time; + } - transformed.blockhash = transaction.__blockHash; - transformed.blockheight = transaction.__height; - transformed.confirmations = confirmations; - var time = transaction.__timestamp ? transaction.__timestamp : Math.round(Date.now() / 1000); - transformed.time = time; - if (transformed.confirmations) { - transformed.blocktime = transformed.time; - } + if(transaction.isCoinbase()) { + transformed.isCoinBase = true; + } - if(transaction.isCoinbase()) { - transformed.isCoinBase = true; - } - - transformed.valueOut = transaction.outputAmount / 1e8; - transformed.size = transaction.toBuffer().length; - if(transaction.hasAllUtxoInfo()) { - transformed.valueIn = transaction.inputAmount / 1e8; - transformed.fees = transaction.getFee() / 1e8; - } - - callback(null, transformed); - - } - ); + transformed.valueOut = transaction.outputAmount / 1e8; + transformed.size = transaction.toBuffer().length; + if(transaction.hasAllUtxoInfo()) { + transformed.valueIn = transaction.inputAmount / 1e8; + transformed.fees = transaction.getFee() / 1e8; + } + callback(null, transformed); }; TxController.prototype.transformInput = function(input, index) { @@ -147,25 +131,20 @@ TxController.prototype.transformInput = function(input, index) { return transformed; }; -TxController.prototype.transformOutput = function(txid, output, index, callback) { - var self = this; +TxController.prototype.transformOutput = function(output, index) { var transformed = { value: (output.satoshis / 1e8).toFixed(8), n: index, scriptPubKey: { - hex: output.script, + hex: output._scriptBuffer.toString('hex'), //reqSigs: null, // TODO - } + }, + spentTxId: output.__spentTxId, + spentIndex: output.__spentIndex //spentTs: undefined // TODO }; - var script; - try { - // Output scripts can be invalid, so we need to try/catch - script = new bitcore.Script(output.script); - } catch (err) { - script = false; - } + var script = output.script; if (script) { transformed.scriptPubKey.asm = script.toASM(); var address = script.toAddress(this.node.network); @@ -174,26 +153,7 @@ TxController.prototype.transformOutput = function(txid, output, index, callback) transformed.scriptPubKey.type = address.type; } } - - var options = { - queryMempool: true - }; - - self.node.services.bitcoind.getInputForOutput( - txid, - index, - options, - function(err, inputResult) { - if (err) { - return callback(err); - } - if (inputResult) { - transformed.spentTxId = inputResult.inputTxId; - transformed.spentIndex = inputResult.inputIndex; - } - callback(null, transformed); - } - ); + return transformed; }; TxController.prototype.transformInvTransaction = function(transaction) { @@ -286,11 +246,20 @@ TxController.prototype.list = function(req, res) { tx.__height = blockInfo.height; tx.__timestamp = block.header.time; + // get previous outputs tx.populateInputs(self.node.services.bitcoind, [], function(err) { if(err) { - return next(err); + return common.handleErrors(err, res); } - self.transformTransaction(tx, next); + + // get spent info + tx.populateSpentInfo(self.node.services.bitcoind, {}, function(err) { + if (err) { + return common.handleErrors(err, res); + } + self.transformTransaction(tx, next); + }); + }); }, function(err, transformed) { if(err) { From 04b0b3904948d4c3dc48e3d55c1e6e2701e82033 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 12 Apr 2016 15:30:47 -0400 Subject: [PATCH 15/57] transaction: include height in spent info --- lib/transactions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/transactions.js b/lib/transactions.js index 505695a..f16b681 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -140,7 +140,8 @@ TxController.prototype.transformOutput = function(output, index) { //reqSigs: null, // TODO }, spentTxId: output.__spentTxId, - spentIndex: output.__spentIndex + spentIndex: output.__spentIndex, + spentHeight: output.__spentHeight //spentTs: undefined // TODO }; From d47527e7d0d96ba753dddf15dab2c2c6b01e2a11 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 11:43:48 -0400 Subject: [PATCH 16/57] transaction: update error handling with codes --- lib/transactions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/transactions.js b/lib/transactions.js index f16b681..72320b9 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -25,7 +25,7 @@ TxController.prototype.transaction = function(req, res, next, txid) { var self = this; this.node.getTransactionWithBlockInfo(txid, function(err, transaction) { - if (err && err instanceof self.node.errors.Transaction.NotFound) { + if (err && err.code === -5) { return common.handleErrors(null, res); } else if(err) { return common.handleErrors(err, res); @@ -193,7 +193,7 @@ TxController.prototype.rawTransaction = function(req, res, next, txid) { var self = this; this.node.getTransaction(txid, function(err, transaction) { - if (err && err instanceof self.node.errors.Transaction.NotFound) { + if (err && err.code === -5) { return common.handleErrors(null, res); } else if(err) { return common.handleErrors(err, res); From 332fd2a01279359c86655b6a158a99c09ebc174c Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 12:02:22 -0400 Subject: [PATCH 17/57] test: update address utxo test --- test/addresses.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/test/addresses.js b/test/addresses.js index 03e6c59..f57b9ec 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -155,7 +155,7 @@ var utxos = [ "timestamp": 1441116143, "satoshis": 53320000, "script": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", - "blockHeight": 534181, + "height": 534181, "confirmations": 50 }, { @@ -165,7 +165,7 @@ var utxos = [ "timestamp": 1441116143, "satoshis": 289829, "script": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", - "blockHeight": 534181, + "height": 534181, "confirmations": 50 } ]; @@ -285,6 +285,8 @@ describe('Addresses', function() { "scriptPubKey": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", "amount": 0.5332, "confirmations": 50, + "height": 534181, + "satoshis": 53320000, "confirmationsFromCache": true } ]; @@ -296,7 +298,12 @@ describe('Addresses', function() { ]; var node = { - getUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos.slice(0, 1)) + services: { + bitcoind: { + height: 534230 + } + }, + getAddressUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos.slice(0, 1)) }; var addresses = new AddressController(node); @@ -351,7 +358,7 @@ describe('Addresses', function() { ]; var node = { - getUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos) + getAddressUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos) }; var addresses = new AddressController(node); From bb901b91bcb0977ffdccb78863300f0630d627de Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 12:05:44 -0400 Subject: [PATCH 18/57] test: standardize indentation to two spaces --- test/addresses.js | 272 ++++++++-------- test/blocks.js | 6 +- test/transactions.js | 748 +++++++++++++++++++++---------------------- 3 files changed, 513 insertions(+), 513 deletions(-) diff --git a/test/addresses.js b/test/addresses.js index f57b9ec..9b619be 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -196,21 +196,21 @@ describe('Addresses', function() { it('should have correct data', function(done) { var insight = { - "addrStr": "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er", - "balance": 0, - "balanceSat": 0, - "totalReceived": 27.82729129, - "totalReceivedSat": 2782729129, - "totalSent": 27.82729129, - "totalSentSat": 2782729129, - "unconfirmedBalance": 0, - "unconfirmedBalanceSat": 0, - "unconfirmedTxApperances": 0, - "txApperances": 2, - "transactions": [ - "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3" - ] + "addrStr": "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er", + "balance": 0, + "balanceSat": 0, + "totalReceived": 27.82729129, + "totalReceivedSat": 2782729129, + "totalSent": 27.82729129, + "totalSentSat": 2782729129, + "unconfirmedBalance": 0, + "unconfirmedBalanceSat": 0, + "unconfirmedTxApperances": 0, + "txApperances": 2, + "transactions": [ + "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", + "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3" + ] }; var res = { @@ -277,18 +277,18 @@ describe('Addresses', function() { describe('/addr/:addr/utxo', function() { it('should have correct data', function(done) { var insight = [ - { - "address": "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK", - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "vout": 1, - "ts": 1441116143, - "scriptPubKey": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", - "amount": 0.5332, - "confirmations": 50, - "height": 534181, - "satoshis": 53320000, - "confirmationsFromCache": true - } + { + "address": "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK", + "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", + "vout": 1, + "ts": 1441116143, + "scriptPubKey": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", + "amount": 0.5332, + "confirmations": 50, + "height": 534181, + "satoshis": 53320000, + "confirmationsFromCache": true + } ]; var todos = [ @@ -327,26 +327,26 @@ describe('Addresses', function() { describe('/addrs/:addrs/utxo', function() { it('should have the correct data', function(done) { var insight = [ - { - "address": "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK", - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "vout": 1, - "ts": 1441116143, - "scriptPubKey": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", - "amount": 0.5332, - "confirmations": 50, - "confirmationsFromCache": true - }, - { - "address": "moZY18rGNmh4YCPeugtGW46AkkWMQttBUD", - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "vout": 2, - "ts": 1441116143, - "scriptPubKey": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", - "amount": 0.00289829, - "confirmations": 50, - "confirmationsFromCache": true - } + { + "address": "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK", + "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", + "vout": 1, + "ts": 1441116143, + "scriptPubKey": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", + "amount": 0.5332, + "confirmations": 50, + "confirmationsFromCache": true + }, + { + "address": "moZY18rGNmh4YCPeugtGW46AkkWMQttBUD", + "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", + "vout": 2, + "ts": 1441116143, + "scriptPubKey": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", + "amount": 0.00289829, + "confirmations": 50, + "confirmationsFromCache": true + } ]; var todos = [ @@ -382,97 +382,97 @@ describe('Addresses', function() { describe('/addrs/:addrs/txs', function() { it('should have correct data', function(done) { var insight = { - "totalItems": 1, - "from": 0, - "to": 1, - "items": [ + "totalItems": 1, + "from": 0, + "to": 1, + "items": [ + { + "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", + "version": 1, + "locktime": 0, + "vin": [ { - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "version": 1, - "locktime": 0, - "vin": [ - { - "txid": "ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3", - "vout": 1, - "scriptSig": { - "asm": "3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d", - "hex": "473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d" - }, - "sequence": 4294967295, - "n": 0, - "addr": "moFfnRwt77pApKnnU6m5uocFaa43aAYpt5", - "valueSat": 53540000, - "value": 0.5354, - "doubleSpentTxID": null - }, - { - "txid": "980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7", - "vout": 2, - "scriptSig": { - "asm": "3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2", - "hex": "473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2" - }, - "sequence": 4294967295, - "n": 1, - "addr": "n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv", - "valueSat": 299829, - "value": 0.00299829, - "doubleSpentTxID": null - } - ], - "vout": [ - { - "value": "0.00220000", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp" - ] - } - }, - { - "value": "0.53320000", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK" - ] - } - }, - { - "value": "0.00289829", - "n": 2, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "moZY18rGNmh4YCPeugtGW46AkkWMQttBUD" - ] - } - } - ], - "blockhash": "0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013", - "blockheight": 534181, - "confirmations": 52, - "time": 1441116143, - "blocktime": 1441116143, - "valueOut": 0.53829829, - "size": 470, - "valueIn": 0.53839829, - "fees": 0.0001, - "firstSeenTs": 1441108193 + "txid": "ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3", + "vout": 1, + "scriptSig": { + "asm": "3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d", + "hex": "473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d" + }, + "sequence": 4294967295, + "n": 0, + "addr": "moFfnRwt77pApKnnU6m5uocFaa43aAYpt5", + "valueSat": 53540000, + "value": 0.5354, + "doubleSpentTxID": null + }, + { + "txid": "980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7", + "vout": 2, + "scriptSig": { + "asm": "3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2", + "hex": "473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2" + }, + "sequence": 4294967295, + "n": 1, + "addr": "n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv", + "valueSat": 299829, + "value": 0.00299829, + "doubleSpentTxID": null } - ] + ], + "vout": [ + { + "value": "0.00220000", + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp" + ] + } + }, + { + "value": "0.53320000", + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK" + ] + } + }, + { + "value": "0.00289829", + "n": 2, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "moZY18rGNmh4YCPeugtGW46AkkWMQttBUD" + ] + } + } + ], + "blockhash": "0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013", + "blockheight": 534181, + "confirmations": 52, + "time": 1441116143, + "blocktime": 1441116143, + "valueOut": 0.53829829, + "size": 470, + "valueIn": 0.53839829, + "fees": 0.0001, + "firstSeenTs": 1441108193 + } + ] }; var todos = { diff --git a/test/blocks.js b/test/blocks.js index eea891c..a346a1a 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -50,9 +50,9 @@ describe('Blocks', function() { 'version': 536870919, 'merkleroot': 'b06437355844b8178173f3e18ca141472e4b0861daa81ef0f701cf9e51f0283e', 'tx': [ - '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', - 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', - '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1' + '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', + 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1' ], 'time': 1440987503, 'nonce': 1868753784, diff --git a/test/transactions.js b/test/transactions.js index 7716486..ab1c559 100644 --- a/test/transactions.js +++ b/test/transactions.js @@ -13,71 +13,71 @@ describe('Transactions', function() { "version": 1, "locktime": 0, "vin": [ - { - "txid": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", - "vout": 0, - "scriptSig": { - "asm": "30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "hex": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" - }, - "sequence": 4294967295, - "n": 0, - "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", - "valueSat": 18535505, - "value": 0.18535505, - "doubleSpentTxID": null, - "isConfirmed": true, - "confirmations": 242, - "unconfirmedInput": false + { + "txid": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", + "vout": 0, + "scriptSig": { + "asm": "30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "hex": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" }, - { - "txid": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", - "vout": 0, - "scriptSig": { - "asm": "30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "hex": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" - }, - "sequence": 4294967295, - "n": 1, - "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", - "valueSat": 16419885, - "value": 0.16419885, - "doubleSpentTxID": null, - "isConfirmed": true, - "confirmations": 242, - "unconfirmedInput": false - } + "sequence": 4294967295, + "n": 0, + "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", + "valueSat": 18535505, + "value": 0.18535505, + "doubleSpentTxID": null, + "isConfirmed": true, + "confirmations": 242, + "unconfirmedInput": false + }, + { + "txid": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", + "vout": 0, + "scriptSig": { + "asm": "30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "hex": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + }, + "sequence": 4294967295, + "n": 1, + "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", + "valueSat": 16419885, + "value": 0.16419885, + "doubleSpentTxID": null, + "isConfirmed": true, + "confirmations": 242, + "unconfirmedInput": false + } ], "vout": [ - { - "value": "0.21247964", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X" - ] - } - }, - { - "value": "0.13677426", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f" - ] - }, - "spentTxId": "614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec", - "spentIndex": 1, - "spentTs": 1440997099 + { + "value": "0.21247964", + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X" + ] } + }, + { + "value": "0.13677426", + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f" + ] + }, + "spentTxId": "614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec", + "spentIndex": 1, + "spentTs": 1440997099 + } ], "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", "blockheight": 533974, @@ -268,197 +268,197 @@ describe('Transactions', function() { var transactions = new TxController(node); var insight = { - "pagesTotal": 1, - "txs": [ + "pagesTotal": 1, + "txs": [ + { + "txid": "25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd", + "version": 1, + "locktime": 0, + "vin": [ { - "txid": "25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd", - "version": 1, - "locktime": 0, - "vin": [ - { - "coinbase": "03d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000", - "sequence": 4294967295, - "n": 0 - } - ], - "vout": [ - { - "value": "12.50040000", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 68bedce8982d25c3b6b03f6238cbad00378b8ead OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF" - ] - } - } - ], - "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", - "blockheight": 533974, - "confirmations": 236, - "time": 1440987503, - "blocktime": 1440987503, - "isCoinBase": true, - "valueOut": 12.5004, - "size": 120 - }, - { - "txid": "b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0", - "version": 1, - "locktime": 0, - "vin": [ - { - "txid": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", - "vout": 0, - "scriptSig": { - "asm": "30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "hex": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" - }, - "sequence": 4294967295, - "n": 0, - "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", - "valueSat": 18535505, - "value": 0.18535505, - "doubleSpentTxID": null - }, - { - "txid": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", - "vout": 0, - "scriptSig": { - "asm": "30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "hex": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" - }, - "sequence": 4294967295, - "n": 1, - "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", - "valueSat": 16419885, - "value": 0.16419885, - "doubleSpentTxID": null - } - ], - "vout": [ - { - "value": "0.21247964", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X" - ] - } - }, - { - "value": "0.13677426", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f" - ] - }, - "spentTxId": "614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec", - "spentIndex": 1, - "spentTs": 1440997099 - } - ], - "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", - "blockheight": 533974, - "confirmations": 236, - "time": 1440987503, - "blocktime": 1440987503, - "valueOut": 0.3492539, - "size": 437, - "valueIn": 0.3495539, - "fees": 0.0003 - }, - { - "txid": "2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1", - "version": 1, - "locktime": 533963, - "vin": [ - { - "txid": "7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06", - "vout": 3, - "scriptSig": { - "asm": "3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d", - "hex": "483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d" - }, - "sequence": 4294967294, - "n": 0, - "addr": "mgZK8zpudWoAaAwpLQSgc9t9PJJyEBpBdJ", - "valueSat": 990000, - "value": 0.0099, - "doubleSpentTxID": null - }, - { - "txid": "ba2f7e668b571bf5080b7c274e6358226f6e16745c2a2e72dbfbcf63828a2d7b", - "vout": 0, - "scriptSig": { - "asm": "3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee", - "hex": "473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee" - }, - "sequence": 4294967294, - "n": 1, - "addr": "n4oM7bPuC4ZPdCEDvtw9xGYQC7jmi5S6F4", - "valueSat": 1960000, - "value": 0.0196, - "doubleSpentTxID": null - } - ], - "vout": [ - { - "value": "0.01940000", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 8e451eec7ca0a1764b4ab119274efdd2727b3c85 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA" - ] - }, - "spentTxId": "9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9", - "spentIndex": 1, - "spentTs": 1440992946 - }, - { - "value": "0.01000000", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 d0fce8f064cd1059a6a11501dd66fe42368572b0 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914d0fce8f064cd1059a6a11501dd66fe42368572b088ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mzZypShcs1B35udnkqeYeJy8rUdgHDDvKG" - ] - }, - "spentTxId": "418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc", - "spentIndex": 34, - "spentTs": 1440999118 - } - ], - "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", - "blockheight": 533974, - "confirmations": 236, - "time": 1440987503, - "blocktime": 1440987503, - "valueOut": 0.0294, - "size": 373, - "valueIn": 0.0295, - "fees": 0.0001 + "coinbase": "03d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000", + "sequence": 4294967295, + "n": 0 } - ] + ], + "vout": [ + { + "value": "12.50040000", + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 68bedce8982d25c3b6b03f6238cbad00378b8ead OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF" + ] + } + } + ], + "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, + "confirmations": 236, + "time": 1440987503, + "blocktime": 1440987503, + "isCoinBase": true, + "valueOut": 12.5004, + "size": 120 + }, + { + "txid": "b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", + "vout": 0, + "scriptSig": { + "asm": "30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "hex": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + }, + "sequence": 4294967295, + "n": 0, + "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", + "valueSat": 18535505, + "value": 0.18535505, + "doubleSpentTxID": null + }, + { + "txid": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", + "vout": 0, + "scriptSig": { + "asm": "30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "hex": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + }, + "sequence": 4294967295, + "n": 1, + "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", + "valueSat": 16419885, + "value": 0.16419885, + "doubleSpentTxID": null + } + ], + "vout": [ + { + "value": "0.21247964", + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X" + ] + } + }, + { + "value": "0.13677426", + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f" + ] + }, + "spentTxId": "614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec", + "spentIndex": 1, + "spentTs": 1440997099 + } + ], + "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, + "confirmations": 236, + "time": 1440987503, + "blocktime": 1440987503, + "valueOut": 0.3492539, + "size": 437, + "valueIn": 0.3495539, + "fees": 0.0003 + }, + { + "txid": "2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1", + "version": 1, + "locktime": 533963, + "vin": [ + { + "txid": "7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06", + "vout": 3, + "scriptSig": { + "asm": "3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d", + "hex": "483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d" + }, + "sequence": 4294967294, + "n": 0, + "addr": "mgZK8zpudWoAaAwpLQSgc9t9PJJyEBpBdJ", + "valueSat": 990000, + "value": 0.0099, + "doubleSpentTxID": null + }, + { + "txid": "ba2f7e668b571bf5080b7c274e6358226f6e16745c2a2e72dbfbcf63828a2d7b", + "vout": 0, + "scriptSig": { + "asm": "3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee", + "hex": "473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee" + }, + "sequence": 4294967294, + "n": 1, + "addr": "n4oM7bPuC4ZPdCEDvtw9xGYQC7jmi5S6F4", + "valueSat": 1960000, + "value": 0.0196, + "doubleSpentTxID": null + } + ], + "vout": [ + { + "value": "0.01940000", + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 8e451eec7ca0a1764b4ab119274efdd2727b3c85 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA" + ] + }, + "spentTxId": "9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9", + "spentIndex": 1, + "spentTs": 1440992946 + }, + { + "value": "0.01000000", + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 d0fce8f064cd1059a6a11501dd66fe42368572b0 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914d0fce8f064cd1059a6a11501dd66fe42368572b088ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mzZypShcs1B35udnkqeYeJy8rUdgHDDvKG" + ] + }, + "spentTxId": "418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc", + "spentIndex": 34, + "spentTs": 1440999118 + } + ], + "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, + "confirmations": 236, + "time": 1440987503, + "blocktime": 1440987503, + "valueOut": 0.0294, + "size": 373, + "valueIn": 0.0295, + "fees": 0.0001 + } + ] }; var todos = { @@ -651,134 +651,134 @@ describe('Transactions', function() { }; var insight = { - "pagesTotal": 1, - "txs": [ + "pagesTotal": 1, + "txs": [ + { + "txid": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", + "version": 1, + "locktime": 534089, + "vin": [ { - "txid": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "version": 1, - "locktime": 534089, - "vin": [ - { - "txid": "ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425", - "vout": 1, - "scriptSig": { - "asm": "3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6", - "hex": "483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6" - }, - "sequence": 4294967294, - "n": 0, - "addr": "msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb", - "valueSat": 2796764565, - "value": 27.96764565, - "doubleSpentTxID": null - } - ], - "vout": [ - { - "value": "27.82729129", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er" - ] - }, - "spentTxId": "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3", - "spentIndex": 0, - "spentTs": 1441072817 - }, - { - "value": "0.14000000", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz" - ] - } - } - ], - "blockhash": "00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520", - "blockheight": 534105, - "confirmations": 119, - "time": 1441068774, - "blocktime": 1441068774, - "valueOut": 27.96729129, - "size": 226, - "valueIn": 27.96764565, - "fees": 0.00035436 + "txid": "ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425", + "vout": 1, + "scriptSig": { + "asm": "3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6", + "hex": "483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6" + }, + "sequence": 4294967294, + "n": 0, + "addr": "msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb", + "valueSat": 2796764565, + "value": 27.96764565, + "doubleSpentTxID": null + } + ], + "vout": [ + { + "value": "27.82729129", + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er" + ] + }, + "spentTxId": "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3", + "spentIndex": 0, + "spentTs": 1441072817 }, { - "txid": "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3", - "version": 1, - "locktime": 534099, - "vin": [ - { - "txid": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "vout": 0, - "scriptSig": { - "asm": "304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24", - "hex": "47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24" - }, - "sequence": 4294967294, - "n": 0, - "addr": "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er", - "valueSat": 2782729129, - "value": 27.82729129, - "doubleSpentTxID": null - } - ], - "vout": [ - { - "value": "27.64693692", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "moSPsU4p2C2gssiniJ1JNH4fB9xs633tLv" - ] - }, - "spentTxId": "661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2", - "spentIndex": 0, - "spentTs": 1441077236 - }, - { - "value": "0.18000000", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 011d2963b619186a318f768dddfd98cd553912a0 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914011d2963b619186a318f768dddfd98cd553912a088ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mfcquSAitCkUKXaYRZTRZQDfUegnL3kDew" - ] - }, - "spentTxId": "71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed", - "spentIndex": 0, - "spentTs": 1441069523 - } - ], - "blockhash": "0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0", - "blockheight": 534110, - "confirmations": 114, - "time": 1441072817, - "blocktime": 1441072817, - "valueOut": 27.82693692, - "size": 225, - "valueIn": 27.82729129, - "fees": 0.00035437 + "value": "0.14000000", + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz" + ] + } } - ] + ], + "blockhash": "00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520", + "blockheight": 534105, + "confirmations": 119, + "time": 1441068774, + "blocktime": 1441068774, + "valueOut": 27.96729129, + "size": 226, + "valueIn": 27.96764565, + "fees": 0.00035436 + }, + { + "txid": "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3", + "version": 1, + "locktime": 534099, + "vin": [ + { + "txid": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", + "vout": 0, + "scriptSig": { + "asm": "304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24", + "hex": "47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24" + }, + "sequence": 4294967294, + "n": 0, + "addr": "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er", + "valueSat": 2782729129, + "value": 27.82729129, + "doubleSpentTxID": null + } + ], + "vout": [ + { + "value": "27.64693692", + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "moSPsU4p2C2gssiniJ1JNH4fB9xs633tLv" + ] + }, + "spentTxId": "661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2", + "spentIndex": 0, + "spentTs": 1441077236 + }, + { + "value": "0.18000000", + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 011d2963b619186a318f768dddfd98cd553912a0 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914011d2963b619186a318f768dddfd98cd553912a088ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "mfcquSAitCkUKXaYRZTRZQDfUegnL3kDew" + ] + }, + "spentTxId": "71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed", + "spentIndex": 0, + "spentTs": 1441069523 + } + ], + "blockhash": "0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0", + "blockheight": 534110, + "confirmations": 114, + "time": 1441072817, + "blocktime": 1441072817, + "valueOut": 27.82693692, + "size": 225, + "valueIn": 27.82729129, + "fees": 0.00035437 + } + ] }; var todos = { From 2ff77801b0027d29b1c59dc345ee035f380fe8b2 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 13:14:52 -0400 Subject: [PATCH 19/57] test: update address test and test upgrades --- lib/addresses.js | 5 ++--- lib/transactions.js | 6 +++--- package.json | 6 +++--- test/addresses.js | 35 ++++++++++++++++++++++++----------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index 7e82030..e30a7fb 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -51,7 +51,6 @@ AddressController.prototype.addressSummarySubQuery = function(req, res, param) { }; AddressController.prototype.getAddressSummary = function(address, options, callback) { - var self = this; this.node.getAddressSummary(address, options, function(err, summary) { if(err) { @@ -130,8 +129,8 @@ AddressController.prototype.utxo = function(req, res) { AddressController.prototype.multiutxo = function(req, res) { var self = this; - this.node.getUnspentOutputs(req.addrs, true, function(err, utxos) { - if(err && err instanceof self.node.errors.NoOutputs) { + this.node.getAddressUnspentOutputs(req.addrs, true, function(err, utxos) { + if(err && err.code === -5) { return res.jsonp([]); } else if(err) { return common.handleErrors(err, res); diff --git a/lib/transactions.js b/lib/transactions.js index 72320b9..a7c0bd0 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -139,9 +139,9 @@ TxController.prototype.transformOutput = function(output, index) { hex: output._scriptBuffer.toString('hex'), //reqSigs: null, // TODO }, - spentTxId: output.__spentTxId, - spentIndex: output.__spentIndex, - spentHeight: output.__spentHeight + spentTxId: output.__spentTxId || null, + spentIndex: output.__spentIndex || null, + spentHeight: output.__spentHeight || null //spentTs: undefined // TODO }; diff --git a/package.json b/package.json index 52e60e7..9432922 100644 --- a/package.json +++ b/package.json @@ -71,10 +71,10 @@ "request": "^2.64.0" }, "devDependencies": { - "chai": "*", - "mocha": "~1.16.2", + "chai": "^3.5.0", + "mocha": "^2.4.5", "proxyquire": "^1.7.2", - "should": "^2.1.1", + "should": "^8.3.1", "sinon": "^1.10.3" } } diff --git a/test/addresses.js b/test/addresses.js index 9b619be..54f3db1 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -334,6 +334,8 @@ describe('Addresses', function() { "ts": 1441116143, "scriptPubKey": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", "amount": 0.5332, + "height": 534181, + "satoshis": 53320000, "confirmations": 50, "confirmationsFromCache": true }, @@ -344,6 +346,8 @@ describe('Addresses', function() { "ts": 1441116143, "scriptPubKey": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", "amount": 0.00289829, + "height": 534181, + "satoshis": 289829, "confirmations": 50, "confirmationsFromCache": true } @@ -358,6 +362,11 @@ describe('Addresses', function() { ]; var node = { + services: { + bitcoind: { + height: 534230 + } + }, getAddressUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos) }; @@ -432,7 +441,10 @@ describe('Addresses', function() { "addresses": [ "mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp" ] - } + }, + "spentHeight": null, + "spentIndex": null, + "spentTxId": null }, { "value": "0.53320000", @@ -444,8 +456,11 @@ describe('Addresses', function() { "type": "pubkeyhash", "addresses": [ "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK" - ] - } + ], + }, + "spentHeight": null, + "spentIndex": null, + "spentTxId": null }, { "value": "0.00289829", @@ -458,7 +473,10 @@ describe('Addresses', function() { "addresses": [ "moZY18rGNmh4YCPeugtGW46AkkWMQttBUD" ] - } + }, + "spentHeight": null, + "spentIndex": null, + "spentTxId": null } ], "blockhash": "0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013", @@ -524,13 +542,8 @@ describe('Addresses', function() { var node = { getAddressHistory: sinon.stub().callsArgWith(2, null, txinfos2), services: { - db: { - tip: { - __height: 534232 - } - }, - address: { - getInputForOutput: sinon.stub().callsArgWith(3, null, false), + bitcoind: { + height: 534232 } }, network: 'testnet' From 13532666c32aa6824e4f1061a77ca248e56643d7 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 13:45:58 -0400 Subject: [PATCH 20/57] test: update block tests --- lib/blocks.js | 3 +-- test/blocks.js | 66 +++++++++++++++++++++----------------------------- 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 572d54a..c94f331 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -47,8 +47,7 @@ BlockController.prototype.block = function(req, res, next, hash) { finish(block); } else { self.node.getBlock(hash, function(err, block) { - if(err && err.message === 'Block not found.') { - // TODO libbitcoind should pass an instance of errors.Block.NotFound + if(err && err.code === -5) { return common.handleErrors(null, res); } else if(err) { return common.handleErrors(err, res); diff --git a/test/blocks.js b/test/blocks.js index a346a1a..e1adf59 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -11,31 +11,33 @@ var blocks = require('./data/blocks.json'); var blockIndexes = { '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7': { hash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - chainWork: '0000000000000000000000000000000000000000000000054626b1839ade284a', - prevHash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + chainwork: '0000000000000000000000000000000000000000000000054626b1839ade284a', + previousblockhash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + nextblockhash: '000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d', height: 533974 }, '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7': { hash: '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', - chainWork: '00000000000000000000000000000000000000000000000544ea52e1575ca753', - prevHash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', + chainwork: '00000000000000000000000000000000000000000000000544ea52e1575ca753', + previousblockhash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', + confirmations: 119, height: 533951 }, '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441': { hash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', - chainWork: '00000000000000000000000000000000000000000000000544ea52e0575ba752', - prevHash: '000000000001b9c41e6c4a7b81a068b50cf3f522ee4ac1e942e75ec16e090547', + chainwork: '00000000000000000000000000000000000000000000000544ea52e0575ba752', + previousblockhash: '000000000001b9c41e6c4a7b81a068b50cf3f522ee4ac1e942e75ec16e090547', height: 533950 }, '000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4': { hash: '000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4', - prevHash: '00000000000000000a9d74a7b527f7b995fc21ceae5aa21087b443469351a362', + previousblockhash: '00000000000000000a9d74a7b527f7b995fc21ceae5aa21087b443469351a362', height: 375493 }, 533974: { hash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - chainWork: '0000000000000000000000000000000000000000000000054626b1839ade284a', - prevHash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + chainwork: '0000000000000000000000000000000000000000000000054626b1839ade284a', + previousblockhash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', height: 533974 } }; @@ -72,14 +74,9 @@ describe('Blocks', function() { getBlock: sinon.stub().callsArgWith(1, null, bitcoreBlock), services: { bitcoind: { - getNextBlockHash: sinon.stub().returns('000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d'), - getBlockIndex: sinon.stub().returns(blockIndexes['0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7']), - isMainChain: sinon.stub().returns(true) - }, - db: { - tip: { - __height: 534092 - } + getBlockHeader: sinon.stub().callsArgWith(1, null, blockIndexes['0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7']), + isMainChain: sinon.stub().returns(true), + height: 534092 } } }; @@ -106,14 +103,9 @@ describe('Blocks', function() { getBlock: sinon.stub().callsArgWith(1, null, block), services: { bitcoind: { - getNextBlockHash: sinon.stub().returns('000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d'), - getBlockIndex: sinon.stub().returns(blockIndexes['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4']), - isMainChain: sinon.stub().returns(true) - }, - db: { - tip: { - __height: 534092 - } + getBlockHeader: sinon.stub().callsArgWith(1, null, blockIndexes['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4']), + isMainChain: sinon.stub().returns(true), + height: 534092 } } }; @@ -174,22 +166,20 @@ describe('Blocks', function() { }; var stub = sinon.stub(); - stub.onFirstCall().callsArgWith(1, null, bitcore.Block.fromBuffer(blocks['000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7'], 'hex')); - stub.onSecondCall().callsArgWith(1, null, bitcore.Block.fromBuffer(blocks['00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441'], 'hex')) + stub.onFirstCall().callsArgWith(1, null, new Buffer(blocks['000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7'], 'hex')); + stub.onSecondCall().callsArgWith(1, null, new Buffer(blocks['00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441'], 'hex')); var hashes = [ - '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', - '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441' + '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', + '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7' ]; var node = { - getBlock: stub, services: { bitcoind: { - getBlockIndex: function(hash) { - return blockIndexes[hash]; - } - }, - db: { + getRawBlock: stub, + getBlockHeader: function(hash, callback) { + callback(null, blockIndexes[hash]); + }, getBlockHashesByTimestamp: sinon.stub().callsArgWith(2, null, hashes) } } @@ -220,8 +210,8 @@ describe('Blocks', function() { var node = { services: { bitcoind: { - getBlockIndex: function(height) { - return blockIndexes[height]; + getBlockHeader: function(height, callback) { + callback(null, blockIndexes[height]); } } } @@ -231,7 +221,7 @@ describe('Blocks', function() { var blocks = new BlockController(node); var insight = { - "blockHash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7" + 'blockHash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7' }; var req = {}; From 29faace44a340c80b9e138b43e5a126dcf132ed2 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 13:54:23 -0400 Subject: [PATCH 21/57] test: standardize quote formatting and fix missing semis --- test/addresses.js | 480 ++++++++++++------------- test/blocks.js | 50 +-- test/transactions.js | 812 ++++++++++++++++++++++--------------------- 3 files changed, 672 insertions(+), 670 deletions(-) diff --git a/test/addresses.js b/test/addresses.js index 54f3db1..b226f37 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -9,130 +9,130 @@ var txinfos = { totalCount: 2, items: [ { - "address": "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er", - "satoshis": 2782729129, - "height": 534105, - "confirmations": 123, - "timestamp": 1441068774, - "fees": 35436, - "outputIndexes": [ + 'address': 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + 'satoshis': 2782729129, + 'height': 534105, + 'confirmations': 123, + 'timestamp': 1441068774, + 'fees': 35436, + 'outputIndexes': [ 0 ], - "inputIndexes": [], - "tx": { - "hash": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "version": 1, - "inputs": [ + 'inputIndexes': [], + 'tx': { + 'hash': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + 'version': 1, + 'inputs': [ { - "prevTxId": "ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425", - "outputIndex": 1, - "sequenceNumber": 4294967294, - "script": "483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6", - "scriptString": "72 0x3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 33 0x03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6", - "output": { - "satoshis": 2796764565, - "script": "76a91488b1fe8aec5ae4358a11447a2f22b2781faedb9b88ac" + 'prevTxId': 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', + 'outputIndex': 1, + 'sequenceNumber': 4294967294, + 'script': '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + 'scriptString': '72 0x3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 33 0x03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + 'output': { + 'satoshis': 2796764565, + 'script': '76a91488b1fe8aec5ae4358a11447a2f22b2781faedb9b88ac' } } ], - "outputs": [ + 'outputs': [ { - "satoshis": 2782729129, - "script": "76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac" + 'satoshis': 2782729129, + 'script': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac' }, { - "satoshis": 14000000, - "script": "76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac" + 'satoshis': 14000000, + 'script': '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac' } ], - "nLockTime": 534089 + 'nLockTime': 534089 } }, { - "address": "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er", - "satoshis": -2782729129, - "height": 534110, - "confirmations": 118, - "timestamp": 1441072817, - "fees": 35437, - "outputIndexes": [], - "inputIndexes": [ - "0" + 'address': 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + 'satoshis': -2782729129, + 'height': 534110, + 'confirmations': 118, + 'timestamp': 1441072817, + 'fees': 35437, + 'outputIndexes': [], + 'inputIndexes': [ + '0' ], - "tx": { - "hash": "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3", - "version": 1, - "inputs": [ + 'tx': { + 'hash': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + 'version': 1, + 'inputs': [ { - "prevTxId": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "outputIndex": 0, - "sequenceNumber": 4294967294, - "script": "47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24", - "scriptString": "71 0x304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 33 0x034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24", - "output": { - "satoshis": 2782729129, - "script": "76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac" + 'prevTxId': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + 'outputIndex': 0, + 'sequenceNumber': 4294967294, + 'script': '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + 'scriptString': '71 0x304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 33 0x034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + 'output': { + 'satoshis': 2782729129, + 'script': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac' } } ], - "outputs": [ + 'outputs': [ { - "satoshis": 2764693692, - "script": "76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac" + 'satoshis': 2764693692, + 'script': '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac' }, { - "satoshis": 18000000, - "script": "76a914011d2963b619186a318f768dddfd98cd553912a088ac" + 'satoshis': 18000000, + 'script': '76a914011d2963b619186a318f768dddfd98cd553912a088ac' } ], - "nLockTime": 534099 + 'nLockTime': 534099 } } ] }; var tx = bitcore.Transaction().fromObject({ - "hash": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "version": 1, - "inputs": [ + 'hash': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + 'version': 1, + 'inputs': [ { - "prevTxId": "ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3", - "outputIndex": 1, - "sequenceNumber": 4294967295, - "script": "473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d", - "scriptString": "71 0x3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 65 0x040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d", - "output": { - "satoshis": 53540000, - "script": "76a91454dcfbff9e109bf369e457f6b0f869f4e647076488ac" + 'prevTxId': 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', + 'outputIndex': 1, + 'sequenceNumber': 4294967295, + 'script': '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + 'scriptString': '71 0x3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 65 0x040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + 'output': { + 'satoshis': 53540000, + 'script': '76a91454dcfbff9e109bf369e457f6b0f869f4e647076488ac' } }, { - "prevTxId": "980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7", - "outputIndex": 2, - "sequenceNumber": 4294967295, - "script": "473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2", - "scriptString": "71 0x3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 65 0x04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2", - "output": { - "satoshis": 299829, - "script": "76a914db731c9ebf3874d75ee26b9c19b692d278c283f788ac" + 'prevTxId': '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', + 'outputIndex': 2, + 'sequenceNumber': 4294967295, + 'script': '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + 'scriptString': '71 0x3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 65 0x04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + 'output': { + 'satoshis': 299829, + 'script': '76a914db731c9ebf3874d75ee26b9c19b692d278c283f788ac' } } ], - "outputs": [ + 'outputs': [ { - "satoshis": 220000, - "script": "76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac" + 'satoshis': 220000, + 'script': '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac' }, { - "satoshis": 53320000, - "script": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac" + 'satoshis': 53320000, + 'script': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac' }, { - "satoshis": 289829, - "script": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac" + 'satoshis': 289829, + 'script': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac' } ], - "nLockTime": 0 + 'nLockTime': 0 }); tx.__height = 534181; @@ -149,24 +149,24 @@ var txinfos2 = { var utxos = [ { - "address": "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK", - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "outputIndex": 1, - "timestamp": 1441116143, - "satoshis": 53320000, - "script": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", - "height": 534181, - "confirmations": 50 + 'address': 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', + 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + 'outputIndex': 1, + 'timestamp': 1441116143, + 'satoshis': 53320000, + 'script': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + 'height': 534181, + 'confirmations': 50 }, { - "address": "moZY18rGNmh4YCPeugtGW46AkkWMQttBUD", - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "outputIndex": 2, - "timestamp": 1441116143, - "satoshis": 289829, - "script": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", - "height": 534181, - "confirmations": 50 + 'address': 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + 'outputIndex': 2, + 'timestamp': 1441116143, + 'satoshis': 289829, + 'script': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', + 'height': 534181, + 'confirmations': 50 } ]; @@ -196,20 +196,20 @@ describe('Addresses', function() { it('should have correct data', function(done) { var insight = { - "addrStr": "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er", - "balance": 0, - "balanceSat": 0, - "totalReceived": 27.82729129, - "totalReceivedSat": 2782729129, - "totalSent": 27.82729129, - "totalSentSat": 2782729129, - "unconfirmedBalance": 0, - "unconfirmedBalanceSat": 0, - "unconfirmedTxApperances": 0, - "txApperances": 2, - "transactions": [ - "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3" + 'addrStr': 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + 'balance': 0, + 'balanceSat': 0, + 'totalReceived': 27.82729129, + 'totalReceivedSat': 2782729129, + 'totalSent': 27.82729129, + 'totalSentSat': 2782729129, + 'unconfirmedBalance': 0, + 'unconfirmedBalanceSat': 0, + 'unconfirmedTxApperances': 0, + 'txApperances': 2, + 'transactions': [ + 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3' ] }; @@ -278,16 +278,16 @@ describe('Addresses', function() { it('should have correct data', function(done) { var insight = [ { - "address": "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK", - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "vout": 1, - "ts": 1441116143, - "scriptPubKey": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", - "amount": 0.5332, - "confirmations": 50, - "height": 534181, - "satoshis": 53320000, - "confirmationsFromCache": true + 'address': 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', + 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + 'vout': 1, + 'ts': 1441116143, + 'scriptPubKey': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + 'amount': 0.5332, + 'confirmations': 50, + 'height': 534181, + 'satoshis': 53320000, + 'confirmationsFromCache': true } ]; @@ -328,28 +328,28 @@ describe('Addresses', function() { it('should have the correct data', function(done) { var insight = [ { - "address": "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK", - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "vout": 1, - "ts": 1441116143, - "scriptPubKey": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", - "amount": 0.5332, - "height": 534181, - "satoshis": 53320000, - "confirmations": 50, - "confirmationsFromCache": true + 'address': 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', + 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + 'vout': 1, + 'ts': 1441116143, + 'scriptPubKey': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + 'amount': 0.5332, + 'height': 534181, + 'satoshis': 53320000, + 'confirmations': 50, + 'confirmationsFromCache': true }, { - "address": "moZY18rGNmh4YCPeugtGW46AkkWMQttBUD", - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "vout": 2, - "ts": 1441116143, - "scriptPubKey": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", - "amount": 0.00289829, - "height": 534181, - "satoshis": 289829, - "confirmations": 50, - "confirmationsFromCache": true + 'address': 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + 'vout': 2, + 'ts': 1441116143, + 'scriptPubKey': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', + 'amount': 0.00289829, + 'height': 534181, + 'satoshis': 289829, + 'confirmations': 50, + 'confirmationsFromCache': true } ]; @@ -391,150 +391,150 @@ describe('Addresses', function() { describe('/addrs/:addrs/txs', function() { it('should have correct data', function(done) { var insight = { - "totalItems": 1, - "from": 0, - "to": 1, - "items": [ + 'totalItems': 1, + 'from': 0, + 'to': 1, + 'items': [ { - "txid": "63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73", - "version": 1, - "locktime": 0, - "vin": [ + 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + 'version': 1, + 'locktime': 0, + 'vin': [ { - "txid": "ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3", - "vout": 1, - "scriptSig": { - "asm": "3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d", - "hex": "473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d" + 'txid': 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', + 'vout': 1, + 'scriptSig': { + 'asm': '3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + 'hex': '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d' }, - "sequence": 4294967295, - "n": 0, - "addr": "moFfnRwt77pApKnnU6m5uocFaa43aAYpt5", - "valueSat": 53540000, - "value": 0.5354, - "doubleSpentTxID": null + 'sequence': 4294967295, + 'n': 0, + 'addr': 'moFfnRwt77pApKnnU6m5uocFaa43aAYpt5', + 'valueSat': 53540000, + 'value': 0.5354, + 'doubleSpentTxID': null }, { - "txid": "980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7", - "vout": 2, - "scriptSig": { - "asm": "3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2", - "hex": "473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2" + 'txid': '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', + 'vout': 2, + 'scriptSig': { + 'asm': '3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + 'hex': '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2' }, - "sequence": 4294967295, - "n": 1, - "addr": "n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv", - "valueSat": 299829, - "value": 0.00299829, - "doubleSpentTxID": null + 'sequence': 4294967295, + 'n': 1, + 'addr': 'n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv', + 'valueSat': 299829, + 'value': 0.00299829, + 'doubleSpentTxID': null } ], - "vout": [ + 'vout': [ { - "value": "0.00220000", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp" + 'value': '0.00220000', + 'n': 0, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp' ] }, - "spentHeight": null, - "spentIndex": null, - "spentTxId": null + 'spentHeight': null, + 'spentIndex': null, + 'spentTxId': null }, { - "value": "0.53320000", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK" + 'value': '0.53320000', + 'n': 1, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK' ], }, - "spentHeight": null, - "spentIndex": null, - "spentTxId": null + 'spentHeight': null, + 'spentIndex': null, + 'spentTxId': null }, { - "value": "0.00289829", - "n": 2, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "moZY18rGNmh4YCPeugtGW46AkkWMQttBUD" + 'value': '0.00289829', + 'n': 2, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD' ] }, - "spentHeight": null, - "spentIndex": null, - "spentTxId": null + 'spentHeight': null, + 'spentIndex': null, + 'spentTxId': null } ], - "blockhash": "0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013", - "blockheight": 534181, - "confirmations": 52, - "time": 1441116143, - "blocktime": 1441116143, - "valueOut": 0.53829829, - "size": 470, - "valueIn": 0.53839829, - "fees": 0.0001, - "firstSeenTs": 1441108193 + 'blockhash': '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013', + 'blockheight': 534181, + 'confirmations': 52, + 'time': 1441116143, + 'blocktime': 1441116143, + 'valueOut': 0.53829829, + 'size': 470, + 'valueIn': 0.53839829, + 'fees': 0.0001, + 'firstSeenTs': 1441108193 } ] }; var todos = { - "items": [ + 'items': [ { - "vin": [ + 'vin': [ { - "scriptSig": { - "asm": "3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d" + 'scriptSig': { + 'asm': '3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d' } }, { - "scriptSig": { - "asm": "3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2" + 'scriptSig': { + 'asm': '3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2' } } ], - "vout": [ + 'vout': [ { - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [] + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [] } }, { - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [] + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [] } }, { - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [] + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [] } } ], - "firstSeenTs": 1441108193 + 'firstSeenTs': 1441108193 } ] }; diff --git a/test/blocks.js b/test/blocks.js index e1adf59..e1ee5d2 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -130,38 +130,38 @@ describe('Blocks', function() { describe('/blocks route', function() { var insight = { - "blocks": [ + 'blocks': [ { - "height": 533951, - "size": 206, - "hash": "000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7", - "time": 1440978683, - "txlength": 1, - "poolInfo": { - "poolName": "AntMiner", - "url": "https://bitmaintech.com/" + 'height': 533951, + 'size': 206, + 'hash': '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', + 'time': 1440978683, + 'txlength': 1, + 'poolInfo': { + 'poolName': 'AntMiner', + 'url': 'https://bitmaintech.com/' } }, { - "height": 533950, - "size": 206, - "hash": "00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441", - "time": 1440977479, - "txlength": 1, - "poolInfo": { - "poolName": "AntMiner", - "url": "https://bitmaintech.com/" + 'height': 533950, + 'size': 206, + 'hash': '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', + 'time': 1440977479, + 'txlength': 1, + 'poolInfo': { + 'poolName': 'AntMiner', + 'url': 'https://bitmaintech.com/' } } ], - "length": 2, - "pagination": { - "current": "2015-08-30", - "currentTs": 1440979199, - "isToday": false, - "more": false, - "next": "2015-08-31", - "prev": "2015-08-29" + 'length': 2, + 'pagination': { + 'current': '2015-08-30', + 'currentTs': 1440979199, + 'isToday': false, + 'more': false, + 'next': '2015-08-31', + 'prev': '2015-08-29' } }; diff --git a/test/transactions.js b/test/transactions.js index ab1c559..c70478c 100644 --- a/test/transactions.js +++ b/test/transactions.js @@ -9,125 +9,125 @@ describe('Transactions', function() { describe('/tx/:txid', function() { it('should have correct data', function(done) { var insight = { - "txid": "b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0", - "version": 1, - "locktime": 0, - "vin": [ + 'txid': 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + 'version': 1, + 'locktime': 0, + 'vin': [ { - "txid": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", - "vout": 0, - "scriptSig": { - "asm": "30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "hex": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + 'txid': '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', + 'vout': 0, + 'scriptSig': { + 'asm': '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + 'hex': '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307' }, - "sequence": 4294967295, - "n": 0, - "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", - "valueSat": 18535505, - "value": 0.18535505, - "doubleSpentTxID": null, - "isConfirmed": true, - "confirmations": 242, - "unconfirmedInput": false + 'sequence': 4294967295, + 'n': 0, + 'addr': 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + 'valueSat': 18535505, + 'value': 0.18535505, + 'doubleSpentTxID': null, + 'isConfirmed': true, + 'confirmations': 242, + 'unconfirmedInput': false }, { - "txid": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", - "vout": 0, - "scriptSig": { - "asm": "30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "hex": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + 'txid': 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', + 'vout': 0, + 'scriptSig': { + 'asm': '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + 'hex': '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307' }, - "sequence": 4294967295, - "n": 1, - "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", - "valueSat": 16419885, - "value": 0.16419885, - "doubleSpentTxID": null, - "isConfirmed": true, - "confirmations": 242, - "unconfirmedInput": false + 'sequence': 4294967295, + 'n': 1, + 'addr': 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + 'valueSat': 16419885, + 'value': 0.16419885, + 'doubleSpentTxID': null, + 'isConfirmed': true, + 'confirmations': 242, + 'unconfirmedInput': false } ], - "vout": [ + 'vout': [ { - "value": "0.21247964", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X" + 'value': '0.21247964', + 'n': 0, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X' ] } }, { - "value": "0.13677426", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f" + 'value': '0.13677426', + 'n': 1, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f' ] }, - "spentTxId": "614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec", - "spentIndex": 1, - "spentTs": 1440997099 + 'spentTxId': '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', + 'spentIndex': 1, + 'spentTs': 1440997099 } ], - "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", - "blockheight": 533974, - "confirmations": 230, - "time": 1440987503, - "blocktime": 1440987503, - "valueOut": 0.3492539, - "size": 437, - "valueIn": 0.3495539, - "fees": 0.0003 + 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + 'blockheight': 533974, + 'confirmations': 230, + 'time': 1440987503, + 'blocktime': 1440987503, + 'valueOut': 0.3492539, + 'size': 437, + 'valueIn': 0.3495539, + 'fees': 0.0003 }; var bitcoreTxObj = { - "hash": "b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0", - "version": 1, - "inputs": [ + 'hash': 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + 'version': 1, + 'inputs': [ { - "prevTxId": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", - "outputIndex": 0, - "sequenceNumber": 4294967295, - "script": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "scriptString": "72 0x30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 65 0x04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "output": { - "satoshis": 18535505, - "script": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac" + 'prevTxId': '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', + 'outputIndex': 0, + 'sequenceNumber': 4294967295, + 'script': '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + 'scriptString': '72 0x30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 65 0x04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + 'output': { + 'satoshis': 18535505, + 'script': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac' } }, { - "prevTxId": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", - "outputIndex": 0, - "sequenceNumber": 4294967295, - "script": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "scriptString": "71 0x30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 65 0x04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "output": { - "satoshis": 16419885, - "script": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac" + 'prevTxId': 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', + 'outputIndex': 0, + 'sequenceNumber': 4294967295, + 'script': '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + 'scriptString': '71 0x30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 65 0x04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + 'output': { + 'satoshis': 16419885, + 'script': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac' } } ], - "outputs": [ + 'outputs': [ { - "satoshis": 21247964, - "script": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac" + 'satoshis': 21247964, + 'script': '76a9144b7b335f978f130269fe661423258ae9642df8a188ac' }, { - "satoshis": 13677426, - "script": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac" + 'satoshis': 13677426, + 'script': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac' } ], - "nLockTime": 0 + 'nLockTime': 0 }; var todos = { @@ -213,11 +213,11 @@ describe('Transactions', function() { it('by block hash', function(done) { var blockHex = '07000020a491892cca9f143f7f00b8d65bbce0204bb32e17e914325fa5010000000000003e28f0519ecf01f7f01ea8da61084b2e4741a18ce1f3738117b84458353764b06fb9e35567f20c1a78eb626f0301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac000000000100000002ad5a14ae9d0f3221b790c4fc590fddceea1456e5692d8c4bf1ff7175f2b0c987000000008b4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff9621ac65bc22ea593ca9a61a8d63e461bf3d3f277989df5d3bd33ddfae0aa1d8000000008a4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff02dc374401000000001976a9144b7b335f978f130269fe661423258ae9642df8a188ac72b3d000000000001976a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac000000000100000002060d3cb6dfb7ffe85e2908010fea63190c9707e96fc7448128eb895b5e222771030000006b483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909dfeffffff7b2d8a8263cffbdb722e2a5c74166e6f2258634e277c0b08f51b578b667e2fba000000006a473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eeefeffffff02209a1d00000000001976a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac40420f00000000001976a914d0fce8f064cd1059a6a11501dd66fe42368572b088accb250800'; var blockIndex = { - "hash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", - "blockheight": 533974, - "chainWork": "0000000000000000000000000000000000000000000000054626b1839ade284a", - "prevHash": "00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4", - "height": 533974 + 'hash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + 'blockheight': 533974, + 'chainWork': '0000000000000000000000000000000000000000000000054626b1839ade284a', + 'prevHash': '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + 'height': 533974 }; var block = bitcore.Block.fromBuffer(new Buffer(blockHex, 'hex')); @@ -268,195 +268,195 @@ describe('Transactions', function() { var transactions = new TxController(node); var insight = { - "pagesTotal": 1, - "txs": [ + 'pagesTotal': 1, + 'txs': [ { - "txid": "25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd", - "version": 1, - "locktime": 0, - "vin": [ + 'txid': '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', + 'version': 1, + 'locktime': 0, + 'vin': [ { - "coinbase": "03d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000", - "sequence": 4294967295, - "n": 0 + 'coinbase': '03d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000', + 'sequence': 4294967295, + 'n': 0 } ], - "vout": [ + 'vout': [ { - "value": "12.50040000", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 68bedce8982d25c3b6b03f6238cbad00378b8ead OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF" + 'value': '12.50040000', + 'n': 0, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 68bedce8982d25c3b6b03f6238cbad00378b8ead OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF' ] } } ], - "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", - "blockheight": 533974, - "confirmations": 236, - "time": 1440987503, - "blocktime": 1440987503, - "isCoinBase": true, - "valueOut": 12.5004, - "size": 120 + 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + 'blockheight': 533974, + 'confirmations': 236, + 'time': 1440987503, + 'blocktime': 1440987503, + 'isCoinBase': true, + 'valueOut': 12.5004, + 'size': 120 }, { - "txid": "b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0", - "version": 1, - "locktime": 0, - "vin": [ + 'txid': 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + 'version': 1, + 'locktime': 0, + 'vin': [ { - "txid": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", - "vout": 0, - "scriptSig": { - "asm": "30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "hex": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + 'txid': '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', + 'vout': 0, + 'scriptSig': { + 'asm': '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + 'hex': '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307' }, - "sequence": 4294967295, - "n": 0, - "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", - "valueSat": 18535505, - "value": 0.18535505, - "doubleSpentTxID": null + 'sequence': 4294967295, + 'n': 0, + 'addr': 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + 'valueSat': 18535505, + 'value': 0.18535505, + 'doubleSpentTxID': null }, { - "txid": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", - "vout": 0, - "scriptSig": { - "asm": "30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", - "hex": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + 'txid': 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', + 'vout': 0, + 'scriptSig': { + 'asm': '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + 'hex': '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307' }, - "sequence": 4294967295, - "n": 1, - "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", - "valueSat": 16419885, - "value": 0.16419885, - "doubleSpentTxID": null + 'sequence': 4294967295, + 'n': 1, + 'addr': 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + 'valueSat': 16419885, + 'value': 0.16419885, + 'doubleSpentTxID': null } ], - "vout": [ + 'vout': [ { - "value": "0.21247964", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X" + 'value': '0.21247964', + 'n': 0, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X' ] } }, { - "value": "0.13677426", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f" + 'value': '0.13677426', + 'n': 1, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f' ] }, - "spentTxId": "614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec", - "spentIndex": 1, - "spentTs": 1440997099 + 'spentTxId': '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', + 'spentIndex': 1, + 'spentTs': 1440997099 } ], - "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", - "blockheight": 533974, - "confirmations": 236, - "time": 1440987503, - "blocktime": 1440987503, - "valueOut": 0.3492539, - "size": 437, - "valueIn": 0.3495539, - "fees": 0.0003 + 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + 'blockheight': 533974, + 'confirmations': 236, + 'time': 1440987503, + 'blocktime': 1440987503, + 'valueOut': 0.3492539, + 'size': 437, + 'valueIn': 0.3495539, + 'fees': 0.0003 }, { - "txid": "2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1", - "version": 1, - "locktime": 533963, - "vin": [ + 'txid': '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1', + 'version': 1, + 'locktime': 533963, + 'vin': [ { - "txid": "7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06", - "vout": 3, - "scriptSig": { - "asm": "3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d", - "hex": "483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d" + 'txid': '7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06', + 'vout': 3, + 'scriptSig': { + 'asm': '3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', + 'hex': '483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d' }, - "sequence": 4294967294, - "n": 0, - "addr": "mgZK8zpudWoAaAwpLQSgc9t9PJJyEBpBdJ", - "valueSat": 990000, - "value": 0.0099, - "doubleSpentTxID": null + 'sequence': 4294967294, + 'n': 0, + 'addr': 'mgZK8zpudWoAaAwpLQSgc9t9PJJyEBpBdJ', + 'valueSat': 990000, + 'value': 0.0099, + 'doubleSpentTxID': null }, { - "txid": "ba2f7e668b571bf5080b7c274e6358226f6e16745c2a2e72dbfbcf63828a2d7b", - "vout": 0, - "scriptSig": { - "asm": "3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee", - "hex": "473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee" + 'txid': 'ba2f7e668b571bf5080b7c274e6358226f6e16745c2a2e72dbfbcf63828a2d7b', + 'vout': 0, + 'scriptSig': { + 'asm': '3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', + 'hex': '473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee' }, - "sequence": 4294967294, - "n": 1, - "addr": "n4oM7bPuC4ZPdCEDvtw9xGYQC7jmi5S6F4", - "valueSat": 1960000, - "value": 0.0196, - "doubleSpentTxID": null + 'sequence': 4294967294, + 'n': 1, + 'addr': 'n4oM7bPuC4ZPdCEDvtw9xGYQC7jmi5S6F4', + 'valueSat': 1960000, + 'value': 0.0196, + 'doubleSpentTxID': null } ], - "vout": [ + 'vout': [ { - "value": "0.01940000", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 8e451eec7ca0a1764b4ab119274efdd2727b3c85 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA" + 'value': '0.01940000', + 'n': 0, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 8e451eec7ca0a1764b4ab119274efdd2727b3c85 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA' ] }, - "spentTxId": "9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9", - "spentIndex": 1, - "spentTs": 1440992946 + 'spentTxId': '9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9', + 'spentIndex': 1, + 'spentTs': 1440992946 }, { - "value": "0.01000000", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 d0fce8f064cd1059a6a11501dd66fe42368572b0 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914d0fce8f064cd1059a6a11501dd66fe42368572b088ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mzZypShcs1B35udnkqeYeJy8rUdgHDDvKG" + 'value': '0.01000000', + 'n': 1, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 d0fce8f064cd1059a6a11501dd66fe42368572b0 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a914d0fce8f064cd1059a6a11501dd66fe42368572b088ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mzZypShcs1B35udnkqeYeJy8rUdgHDDvKG' ] }, - "spentTxId": "418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc", - "spentIndex": 34, - "spentTs": 1440999118 + 'spentTxId': '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc', + 'spentIndex': 34, + 'spentTs': 1440999118 } ], - "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", - "blockheight": 533974, - "confirmations": 236, - "time": 1440987503, - "blocktime": 1440987503, - "valueOut": 0.0294, - "size": 373, - "valueIn": 0.0295, - "fees": 0.0001 + 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + 'blockheight': 533974, + 'confirmations': 236, + 'time': 1440987503, + 'blocktime': 1440987503, + 'valueOut': 0.0294, + 'size': 373, + 'valueIn': 0.0295, + 'fees': 0.0001 } ] }; @@ -514,7 +514,7 @@ describe('Transactions', function() { ] } ] - } + }; var req = { query: { @@ -537,62 +537,62 @@ describe('Transactions', function() { var txinfos = [ { tx: bitcore.Transaction().fromObject({ - "hash": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "version": 1, - "inputs": [ + 'hash': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + 'version': 1, + 'inputs': [ { - "prevTxId": "ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425", - "outputIndex": 1, - "sequenceNumber": 4294967294, - "script": "483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6", - "scriptString": "72 0x3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 33 0x03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6", - "output": { - "satoshis": 2796764565, - "script": "76a91488b1fe8aec5ae4358a11447a2f22b2781faedb9b88ac" + 'prevTxId': 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', + 'outputIndex': 1, + 'sequenceNumber': 4294967294, + 'script': '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + 'scriptString': '72 0x3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 33 0x03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + 'output': { + 'satoshis': 2796764565, + 'script': '76a91488b1fe8aec5ae4358a11447a2f22b2781faedb9b88ac' } } ], - "outputs": [ + 'outputs': [ { - "satoshis": 2782729129, - "script": "76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac" + 'satoshis': 2782729129, + 'script': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac' }, { - "satoshis": 14000000, - "script": "76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac" + 'satoshis': 14000000, + 'script': '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac' } ], - "nLockTime": 534089 + 'nLockTime': 534089 }) }, { tx: bitcore.Transaction().fromObject({ - "hash": "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3", - "version": 1, - "inputs": [ + 'hash': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + 'version': 1, + 'inputs': [ { - "prevTxId": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "outputIndex": 0, - "sequenceNumber": 4294967294, - "script": "47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24", - "scriptString": "71 0x304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 33 0x034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24", - "output": { - "satoshis": 2782729129, - "script": "76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac" + 'prevTxId': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + 'outputIndex': 0, + 'sequenceNumber': 4294967294, + 'script': '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + 'scriptString': '71 0x304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 33 0x034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + 'output': { + 'satoshis': 2782729129, + 'script': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac' } } ], - "outputs": [ + 'outputs': [ { - "satoshis": 2764693692, - "script": "76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac" + 'satoshis': 2764693692, + 'script': '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac' }, { - "satoshis": 18000000, - "script": "76a914011d2963b619186a318f768dddfd98cd553912a088ac" + 'satoshis': 18000000, + 'script': '76a914011d2963b619186a318f768dddfd98cd553912a088ac' } ], - "nLockTime": 534099 + 'nLockTime': 534099 }) } ]; @@ -633,12 +633,12 @@ describe('Transactions', function() { data = { inputTxId: '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2', inputIndex: 0 - } + }; } else if (outputIndex === 1) { data = { inputTxId: '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed', inputIndex: 0 - } + }; } } setImmediate(function() { @@ -651,170 +651,170 @@ describe('Transactions', function() { }; var insight = { - "pagesTotal": 1, - "txs": [ + 'pagesTotal': 1, + 'txs': [ { - "txid": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "version": 1, - "locktime": 534089, - "vin": [ + 'txid': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + 'version': 1, + 'locktime': 534089, + 'vin': [ { - "txid": "ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425", - "vout": 1, - "scriptSig": { - "asm": "3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6", - "hex": "483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6" + 'txid': 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', + 'vout': 1, + 'scriptSig': { + 'asm': '3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + 'hex': '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6' }, - "sequence": 4294967294, - "n": 0, - "addr": "msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb", - "valueSat": 2796764565, - "value": 27.96764565, - "doubleSpentTxID": null + 'sequence': 4294967294, + 'n': 0, + 'addr': 'msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb', + 'valueSat': 2796764565, + 'value': 27.96764565, + 'doubleSpentTxID': null } ], - "vout": [ + 'vout': [ { - "value": "27.82729129", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er" + 'value': '27.82729129', + 'n': 0, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er' ] }, - "spentTxId": "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3", - "spentIndex": 0, - "spentTs": 1441072817 + 'spentTxId': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + 'spentIndex': 0, + 'spentTs': 1441072817 }, { - "value": "0.14000000", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz" + 'value': '0.14000000', + 'n': 1, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz' ] } } ], - "blockhash": "00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520", - "blockheight": 534105, - "confirmations": 119, - "time": 1441068774, - "blocktime": 1441068774, - "valueOut": 27.96729129, - "size": 226, - "valueIn": 27.96764565, - "fees": 0.00035436 + 'blockhash': '00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520', + 'blockheight': 534105, + 'confirmations': 119, + 'time': 1441068774, + 'blocktime': 1441068774, + 'valueOut': 27.96729129, + 'size': 226, + 'valueIn': 27.96764565, + 'fees': 0.00035436 }, { - "txid": "01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3", - "version": 1, - "locktime": 534099, - "vin": [ + 'txid': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + 'version': 1, + 'locktime': 534099, + 'vin': [ { - "txid": "bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7", - "vout": 0, - "scriptSig": { - "asm": "304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24", - "hex": "47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24" + 'txid': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + 'vout': 0, + 'scriptSig': { + 'asm': '304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + 'hex': '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24' }, - "sequence": 4294967294, - "n": 0, - "addr": "mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er", - "valueSat": 2782729129, - "value": 27.82729129, - "doubleSpentTxID": null + 'sequence': 4294967294, + 'n': 0, + 'addr': 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + 'valueSat': 2782729129, + 'value': 27.82729129, + 'doubleSpentTxID': null } ], - "vout": [ + 'vout': [ { - "value": "27.64693692", - "n": 0, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "moSPsU4p2C2gssiniJ1JNH4fB9xs633tLv" + 'value': '27.64693692', + 'n': 0, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'moSPsU4p2C2gssiniJ1JNH4fB9xs633tLv' ] }, - "spentTxId": "661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2", - "spentIndex": 0, - "spentTs": 1441077236 + 'spentTxId': '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2', + 'spentIndex': 0, + 'spentTs': 1441077236 }, { - "value": "0.18000000", - "n": 1, - "scriptPubKey": { - "asm": "OP_DUP OP_HASH160 011d2963b619186a318f768dddfd98cd553912a0 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914011d2963b619186a318f768dddfd98cd553912a088ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ - "mfcquSAitCkUKXaYRZTRZQDfUegnL3kDew" + 'value': '0.18000000', + 'n': 1, + 'scriptPubKey': { + 'asm': 'OP_DUP OP_HASH160 011d2963b619186a318f768dddfd98cd553912a0 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a914011d2963b619186a318f768dddfd98cd553912a088ac', + 'reqSigs': 1, + 'type': 'pubkeyhash', + 'addresses': [ + 'mfcquSAitCkUKXaYRZTRZQDfUegnL3kDew' ] }, - "spentTxId": "71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed", - "spentIndex": 0, - "spentTs": 1441069523 + 'spentTxId': '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed', + 'spentIndex': 0, + 'spentTs': 1441069523 } ], - "blockhash": "0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0", - "blockheight": 534110, - "confirmations": 114, - "time": 1441072817, - "blocktime": 1441072817, - "valueOut": 27.82693692, - "size": 225, - "valueIn": 27.82729129, - "fees": 0.00035437 + 'blockhash': '0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0', + 'blockheight': 534110, + 'confirmations': 114, + 'time': 1441072817, + 'blocktime': 1441072817, + 'valueOut': 27.82693692, + 'size': 225, + 'valueIn': 27.82729129, + 'fees': 0.00035437 } ] }; var todos = { - "txs": [ + 'txs': [ { - "vin": [ + 'vin': [ ], - "vout": [ + 'vout': [ { - "scriptPubKey": { - "reqSigs": 1 + 'scriptPubKey': { + 'reqSigs': 1 }, - "spentTs": 1441072817 + 'spentTs': 1441072817 }, { - "scriptPubKey": { - "reqSigs": 1 + 'scriptPubKey': { + 'reqSigs': 1 } } ] }, { - "vin": [ + 'vin': [ ], - "vout": [ + 'vout': [ { - "scriptPubKey": { - "reqSigs": 1 + 'scriptPubKey': { + 'reqSigs': 1 }, - "spentTs": 1441077236 + 'spentTs': 1441077236 }, { - "scriptPubKey": { - "reqSigs": 1 + 'scriptPubKey': { + 'reqSigs': 1 }, - "spentTs": 1441069523 + 'spentTs': 1441069523 } ] } @@ -864,17 +864,17 @@ describe('Transactions', function() { describe('#transformInvTransaction', function() { it('should give the correct data', function() { var insight = { - "txid": "a15a7c257af596704390d345ff3ea2eed4cd02ce8bfb8afb700bff82257e49fb", - "valueOut": 0.02038504, - "vout": [ + 'txid': 'a15a7c257af596704390d345ff3ea2eed4cd02ce8bfb8afb700bff82257e49fb', + 'valueOut': 0.02038504, + 'vout': [ { - "3DQYCLG6rZdtV2Xw8y4YtozZjNHYoKsLuo": 45000 + '3DQYCLG6rZdtV2Xw8y4YtozZjNHYoKsLuo': 45000 }, { - "12WvZmssxT85f81dD6wcmWznxbnFkEpNMS": 1993504 + '12WvZmssxT85f81dD6wcmWznxbnFkEpNMS': 1993504 } ], - "isRBF": false, + 'isRBF': false }; var rawTx = '01000000011760bc271a397bfb65b7506d430d96ebb1faff467ed957516238a9670e806a86010000006b483045022100f0056ae68a34cdb4194d424bd727c18f82653bca2a198e0d55ab6b4ee88bbdb902202a5745af4f72a5dbdca1e3d683af4667728a8b20e8001e0f8308a4d329ce3f96012102f3af6e66b61c9d99c74d9a9c3c1bec014a8c05d28bf339c8f5f395b5ce319e7dffffffff02c8af00000000000017a9148083b541ea15f1d18c5ca5e1fd47f9035cce24ed87206b1e00000000001976a91410a0e70cd91a45e0e6e409e227ab285bd61592b188ac00000000'; @@ -891,14 +891,14 @@ describe('Transactions', function() { }); it('will not include null values in vout array', function() { var insight = { - "txid": "716d54157c31e52c820494c6c2b8af1b64352049f4dcc80632aa15742a7f82c4", - "valueOut": 12.5002, - "vout": [ + 'txid': '716d54157c31e52c820494c6c2b8af1b64352049f4dcc80632aa15742a7f82c4', + 'valueOut': 12.5002, + 'vout': [ { - "n4eY3qiP9pi32MWC6FcJFHciSsfNiYFYgR": 12.5002 * 1e8 + 'n4eY3qiP9pi32MWC6FcJFHciSsfNiYFYgR': 12.5002 * 1e8 } ], - "isRBF": false, + 'isRBF': false }; var rawTx = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0403ebc108ffffffff04a0ca814a000000001976a914fdb9fb622b0db8d9121475a983288a0876f4de4888ac0000000000000000226a200000000000000000000000000000000000000000000000000000ffff0000000000000000000000001b6a1976a914fdb9fb622b0db8d9121475a983288a0876f4de4888ac0000000000000000326a303a791c8e85200500d89769b4f958e4db6b3ec388ddaa30233c4517d942d440c24ae903bff40d97ca06465fcf2714000000000000'; @@ -914,13 +914,15 @@ describe('Transactions', function() { should(result).eql(insight); }); it('should detect RBF txs', function() { - var testCases = [{ - rawTx: '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f93598893578893588851ffffffff01501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', - expected: false, - }, { - rawTx: '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f935988935788935888510000000001501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', - expected: true, - }, ]; + var testCases = [ + { + rawTx: '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f93598893578893588851ffffffff01501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', + expected: false, + }, { + rawTx: '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f935988935788935888510000000001501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', + expected: true, + }, + ]; var node = { network: bitcore.Networks.livenet From f87bdea8fb4d7e3b3ab741d5e2d28d137034bdf6 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 14:03:57 -0400 Subject: [PATCH 22/57] test: update status tests --- test/status.js | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/test/status.js b/test/status.js index 8b791d6..9c2119a 100644 --- a/test/status.js +++ b/test/status.js @@ -31,13 +31,9 @@ describe('Status', function() { var node = { services: { bitcoind: { - getInfo: sinon.stub().returns(info), - getBestBlockHash: sinon.stub().returns(outSetInfo.bestblock) - }, - db: { - tip: { - hash: outSetInfo.bestblock - } + getInfo: sinon.stub().callsArgWith(0, null, info), + getBestBlockHash: sinon.stub().callsArgWith(0, null, outSetInfo.bestblock), + tiphash: outSetInfo.bestblock } } }; @@ -118,15 +114,10 @@ describe('Status', function() { it('should have correct data', function(done) { var node = { services: { - db: { - tip: { - __height: 500000 - } - }, bitcoind: { height: 500000, - isSynced: sinon.stub().returns(true), - syncPercentage: sinon.stub().returns(99.99) + isSynced: sinon.stub().callsArgWith(0, null, true), + syncPercentage: sinon.stub().callsArgWith(0, null, 99.99) } } }; From c68b9e143e43253d5ea362a9ba6d335e14223748 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 14:56:54 -0400 Subject: [PATCH 23/57] test: update transaction tests --- lib/transactions.js | 2 +- test/transactions.js | 158 +++++++++++++++++++++---------------------- 2 files changed, 79 insertions(+), 81 deletions(-) diff --git a/lib/transactions.js b/lib/transactions.js index a7c0bd0..c63d2b5 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -140,7 +140,7 @@ TxController.prototype.transformOutput = function(output, index) { //reqSigs: null, // TODO }, spentTxId: output.__spentTxId || null, - spentIndex: output.__spentIndex || null, + spentIndex: _.isUndefined(output.__spentIndex) ? null : output.__spentIndex, spentHeight: output.__spentHeight || null //spentTs: undefined // TODO }; diff --git a/test/transactions.js b/test/transactions.js index c70478c..75a7926 100644 --- a/test/transactions.js +++ b/test/transactions.js @@ -60,7 +60,10 @@ describe('Transactions', function() { 'addresses': [ 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X' ] - } + }, + 'spentTxId': null, + 'spentIndex': null, + 'spentHeight': null }, { 'value': '0.13677426', @@ -76,6 +79,7 @@ describe('Transactions', function() { }, 'spentTxId': '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', 'spentIndex': 1, + 'spentHeight': 10, 'spentTs': 1440997099 } ], @@ -168,29 +172,16 @@ describe('Transactions', function() { bitcoreTx.populateInputs = sinon.stub().callsArg(2); bitcoreTx.toObject = sinon.stub().returns(bitcoreTxObj); + bitcoreTx.outputs[1].__spentTxId = spentTxId; + bitcoreTx.outputs[1].__spentIndex = spentIndex; + bitcoreTx.outputs[1].__spentHeight = 10; + var node = { - getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, bitcoreTx), + getTransactionWithBlockInfo: sinon.stub().callsArgWith(1, null, bitcoreTx), services: { - db: { - tip: { - __height: 534203 - } + bitcoind: { + height: 534203 }, - address: { - getInputForOutput: function(txid, outputIndex, options, callback) { - var data = false; - if (txid === 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0' && - outputIndex === 1) { - data = { - inputTxId: spentTxId, - inputIndex: spentIndex - } - } - setImmediate(function() { - callback(null, data); - }); - } - } }, network: 'testnet' }; @@ -210,13 +201,17 @@ describe('Transactions', function() { }); describe('/txs', function() { + var sandbox = sinon.sandbox.create(); + afterEach(function() { + sandbox.restore(); + }); it('by block hash', function(done) { var blockHex = '07000020a491892cca9f143f7f00b8d65bbce0204bb32e17e914325fa5010000000000003e28f0519ecf01f7f01ea8da61084b2e4741a18ce1f3738117b84458353764b06fb9e35567f20c1a78eb626f0301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac000000000100000002ad5a14ae9d0f3221b790c4fc590fddceea1456e5692d8c4bf1ff7175f2b0c987000000008b4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff9621ac65bc22ea593ca9a61a8d63e461bf3d3f277989df5d3bd33ddfae0aa1d8000000008a4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff02dc374401000000001976a9144b7b335f978f130269fe661423258ae9642df8a188ac72b3d000000000001976a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac000000000100000002060d3cb6dfb7ffe85e2908010fea63190c9707e96fc7448128eb895b5e222771030000006b483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909dfeffffff7b2d8a8263cffbdb722e2a5c74166e6f2258634e277c0b08f51b578b667e2fba000000006a473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eeefeffffff02209a1d00000000001976a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac40420f00000000001976a914d0fce8f064cd1059a6a11501dd66fe42368572b088accb250800'; var blockIndex = { 'hash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', 'blockheight': 533974, - 'chainWork': '0000000000000000000000000000000000000000000000054626b1839ade284a', - 'prevHash': '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + 'chainwork': '0000000000000000000000000000000000000000000000054626b1839ade284a', + 'previousblockhash': '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', 'height': 533974 }; @@ -226,21 +221,33 @@ describe('Transactions', function() { getBlock: sinon.stub().callsArgWith(1, null, block), services: { bitcoind: { - getBlockIndex: sinon.stub().returns(blockIndex) - }, - db: { - tip: { - __height: 534209 - } - }, - address: { - getInputForOutput: sinon.stub().callsArgWith(3, null, false), + getBlockHeader: sinon.stub().callsArgWith(1, null, blockIndex), + height: 534209 } }, network: 'testnet' }; - bitcore.Transaction.prototype.populateInputs = function(db, pool, callback) { + bitcore.Transaction.prototype.populateSpentInfo = _.noop(); + sandbox.stub(bitcore.Transaction.prototype, 'populateSpentInfo', function(db, options, callback) { + if (this.hash === 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0') { + this.outputs[1].__spentTxId = '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec'; + this.outputs[1].__spentIndex = 1; + this.outputs[1].__spentHeight = 200; + } else if (this.hash === '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1') { + this.outputs[0].__spentTxId = '9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9'; + this.outputs[0].__spentIndex = 1; + this.outputs[0].__spentHeight = 200; + + this.outputs[1].__spentTxId = '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc'; + this.outputs[1].__spentIndex = 34; + this.outputs[1].__spentHeight = 200; + } + callback(); + }); + + bitcore.Transaction.prototype.populateInputs = _.noop(); + sandbox.stub(bitcore.Transaction.prototype, 'populateInputs', function(db, pool, callback) { if(this.hash === 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0') { this.inputs[0].output = new bitcore.Transaction.Output({ satoshis: 18535505, @@ -263,7 +270,7 @@ describe('Transactions', function() { } callback(); - }; + }); var transactions = new TxController(node); @@ -293,7 +300,10 @@ describe('Transactions', function() { 'addresses': [ 'mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF' ] - } + }, + 'spentTxId': null, + 'spentIndex': null, + 'spentHeight': null } ], 'blockhash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', @@ -351,7 +361,10 @@ describe('Transactions', function() { 'addresses': [ 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X' ] - } + }, + 'spentTxId': null, + 'spentIndex': null, + 'spentHeight': null }, { 'value': '0.13677426', @@ -367,6 +380,7 @@ describe('Transactions', function() { }, 'spentTxId': '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', 'spentIndex': 1, + 'spentHeight': 200, 'spentTs': 1440997099 } ], @@ -429,6 +443,7 @@ describe('Transactions', function() { }, 'spentTxId': '9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9', 'spentIndex': 1, + 'spentHeight': 200, 'spentTs': 1440992946 }, { @@ -445,6 +460,7 @@ describe('Transactions', function() { }, 'spentTxId': '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc', 'spentIndex': 34, + 'spentHeight': 200, 'spentTs': 1440999118 } ], @@ -485,9 +501,7 @@ describe('Transactions', function() { scriptPubKey: { reqSigs: 1 }, - spentIndex: 1, - spentTs: 1440997099, - spentTxId: '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec' + spentTs: 1440997099 } ] }, @@ -499,17 +513,13 @@ describe('Transactions', function() { scriptPubKey: { reqSigs: 1 }, - spentIndex: 1, - spentTs: 1440992946, - spentTxId: '9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9' + spentTs: 1440992946 }, { scriptPubKey: { reqSigs: 1 }, - spentIndex: 34, - spentTs: 1440999118, - spentTxId: '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc' + spentTs: 1440999118 } ] } @@ -524,7 +534,7 @@ describe('Transactions', function() { var res = { jsonp: function(data) { - var merged = _.merge(data, todos); + _.merge(data, todos); should(data).eql(insight); done(); } @@ -610,41 +620,23 @@ describe('Transactions', function() { txinfos[1].tx.__timestamp = 1441072817; txinfos[1].tx.__height = 534110; + txinfos[0].tx.outputs[0].__spentTxId = '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3'; + txinfos[0].tx.outputs[0].__spentIndex = 0; + txinfos[0].tx.outputs[0].__spentHeight = 199; + + txinfos[1].tx.outputs[0].__spentTxId = '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2'; + txinfos[1].tx.outputs[0].__spentIndex = 0; + txinfos[1].tx.outputs[0].__spentHeight = 134; + + txinfos[1].tx.outputs[1].__spentTxId = '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed'; + txinfos[1].tx.outputs[1].__spentIndex = 0; + txinfos[1].tx.outputs[1].__spentHeight = 112; + var node = { getAddressHistory: sinon.stub().callsArgWith(2, null, historyResult), services: { - db: { - tip: { - __height: 534223 - } - }, - address: { - getInputForOutput: function(txid, outputIndex, options, callback) { - var data = false; - if (txid === 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7') { - if (outputIndex === 0) { - data = { - inputTxId: '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', - inputIndex: 0 - }; - } - } else if (txid === '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3') { - if (outputIndex === 0) { - data = { - inputTxId: '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2', - inputIndex: 0 - }; - } else if (outputIndex === 1) { - data = { - inputTxId: '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed', - inputIndex: 0 - }; - } - } - setImmediate(function() { - callback(null, data); - }); - } + bitcoind: { + height: 534223 } }, network: 'testnet' @@ -688,6 +680,7 @@ describe('Transactions', function() { }, 'spentTxId': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', 'spentIndex': 0, + 'spentHeight': 199, 'spentTs': 1441072817 }, { @@ -701,7 +694,10 @@ describe('Transactions', function() { 'addresses': [ 'muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz' ] - } + }, + 'spentTxId': null, + 'spentIndex': null, + 'spentHeight': null } ], 'blockhash': '00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520', @@ -749,6 +745,7 @@ describe('Transactions', function() { }, 'spentTxId': '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2', 'spentIndex': 0, + 'spentHeight': 134, 'spentTs': 1441077236 }, { @@ -765,6 +762,7 @@ describe('Transactions', function() { }, 'spentTxId': '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed', 'spentIndex': 0, + 'spentHeight': 112, 'spentTs': 1441069523 } ], @@ -845,7 +843,7 @@ describe('Transactions', function() { var hex = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000'; var node = { - getTransaction: sinon.stub().callsArgWith(2, null, bitcore.Transaction().fromBuffer(new Buffer(hex, 'hex'))) + getTransaction: sinon.stub().callsArgWith(1, null, bitcore.Transaction().fromBuffer(new Buffer(hex, 'hex'))) }; var transactions = new TxController(node); From 6ec263692bf0a714a6d82fa4b5782da8d98e10d8 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 14:59:43 -0400 Subject: [PATCH 24/57] test: run node v4 with travis ci --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cb81fca..aa9deeb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: - 'v0.12.7' + - 'v4' install: - npm install From b686c5bea924e9a9b4f4bfd75d29978740b68c37 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 15 Apr 2016 15:48:18 -0400 Subject: [PATCH 25/57] blocks: fix null prevhash issue --- lib/blocks.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/blocks.js b/lib/blocks.js index c94f331..565965b 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -84,6 +84,15 @@ BlockController.prototype.rawBlock = function(req, res, next, blockArg) { }; +BlockController.prototype._normalizePrevHash = function(hash) { + // TODO fix bitcore to give back null instead of null hash + if (hash !== '0000000000000000000000000000000000000000000000000000000000000000') { + return hash; + } else { + return null; + } +}; + BlockController.prototype.transformBlock = function(block, info) { var blockObj = block.toObject(); var transactionIds = blockObj.transactions.map(function(tx) { @@ -101,7 +110,7 @@ BlockController.prototype.transformBlock = function(block, info) { bits: blockObj.header.bits.toString(16), difficulty: block.header.getDifficulty(), chainwork: info.chainwork, - previousblockhash: blockObj.header.prevHash, + previousblockhash: this._normalizePrevHash(blockObj.header.prevHash), nextblockhash: info.nextblockhash, reward: this.getBlockReward(info.height) / 1e8, isMainChain: (info.confirmations !== -1), From e1df171f9516e8fade95fbecb284c384e6e10adb Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 20 Apr 2016 10:54:10 -0400 Subject: [PATCH 26/57] blocks: cache block header info with next block with 6 confirmations --- lib/blocks.js | 26 +++++++++++++------------- test/blocks.js | 1 + 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 565965b..71eb7de 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -13,7 +13,7 @@ function BlockController(node) { this.node = node; this.blockSummaryCache = LRU(1000000); - this.blockSummaryCacheConfirmations = 6; + this.blockCacheConfirmations = 6; this.blockCache = LRU(1000); this.poolStrings = {}; @@ -35,16 +35,12 @@ var BLOCK_LIMIT = 200; BlockController.prototype.block = function(req, res, next, hash) { var self = this; - function finish(blockResult) { - blockResult.confirmations = self.node.services.bitcoind.height - blockResult.height + 1; - req.block = blockResult; + var blockCached = self.blockCache.get(hash); + + if (blockCached) { + blockCached.confirmations = self.node.services.bitcoind.height - blockCached.height + 1; + req.block = blockCached; next(); - } - - var block = self.blockCache.get(hash); - - if (block) { - finish(block); } else { self.node.getBlock(hash, function(err, block) { if(err && err.code === -5) { @@ -57,8 +53,11 @@ BlockController.prototype.block = function(req, res, next, hash) { return common.handleErrors(err, res); } var blockResult = self.transformBlock(block, info); - self.blockCache.set(hash, blockResult); - finish(blockResult); + if (blockResult.confirmations >= self.blockCacheConfirmations) { + self.blockCache.set(hash, blockResult); + } + req.block = blockResult; + next(); }); }); } @@ -110,6 +109,7 @@ BlockController.prototype.transformBlock = function(block, info) { bits: blockObj.header.bits.toString(16), difficulty: block.header.getDifficulty(), chainwork: info.chainwork, + confirmations: info.confirmations, previousblockhash: this._normalizePrevHash(blockObj.header.prevHash), nextblockhash: info.nextblockhash, reward: this.getBlockReward(info.height) / 1e8, @@ -193,7 +193,7 @@ BlockController.prototype._getBlockSummary = function(hash, moreTs, next) { }; var confirmations = self.node.services.bitcoind.height - height + 1; - if (confirmations >= self.blockSummaryCacheConfirmations) { + if (confirmations >= self.blockCacheConfirmations) { self.blockSummaryCache.set(hash, summary); } diff --git a/test/blocks.js b/test/blocks.js index e1ee5d2..d670597 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -14,6 +14,7 @@ var blockIndexes = { chainwork: '0000000000000000000000000000000000000000000000054626b1839ade284a', previousblockhash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', nextblockhash: '000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d', + confirmations: 119, height: 533974 }, '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7': { From 6e5dbfd22a8618d15f57e6d7d838de8d3f0d735f Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 20 Apr 2016 14:07:29 -0400 Subject: [PATCH 27/57] utils: update estimatefee --- lib/utils.js | 19 +++++++++++++++---- test/utils.js | 10 +++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 54320b4..1028fb5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,5 +1,8 @@ 'use strict'; + var _ = require('lodash'); +var async = require('async'); +var common = require('./common'); function UtilsController(node) { this.node = node; @@ -10,14 +13,22 @@ UtilsController.prototype.estimateFee = function(req, res) { var args = req.query.nbBlocks || '2'; var nbBlocks = args.split(','); - var result = nbBlocks.map(function(n) { + async.map(nbBlocks, function(n, next) { var num = parseInt(n); // Insight and Bitcoin JSON-RPC return bitcoin for this value (instead of satoshis). - var fee = self.node.services.bitcoind.estimateFee(num) / 1e8; - return [num, fee]; + self.node.services.bitcoind.estimateFee(num, function(err, fee) { + if (err) { + return next(err); + } + next(null, [num, fee]); + }); + }, function(err, result) { + if (err) { + return common.handleErrors(err, res); + } + res.jsonp(_.zipObject(result)); }); - res.jsonp(_.zipObject(result)); }; module.exports = UtilsController; diff --git a/test/utils.js b/test/utils.js index 4fda011..41c84a9 100644 --- a/test/utils.js +++ b/test/utils.js @@ -10,12 +10,12 @@ describe('Utils', function() { var node = { services: { bitcoind: { - estimateFee: function(blocks) { + estimateFee: function(blocks, callback) { switch(blocks) { - case 1: - return 1000; - case 3: - return 3000; + case 1: + return callback(null, 1000 / 1e8); + case 3: + return callback(null, 3000 / 1e8); } } } From 3e40d71c518510f43525ee8fa10c3c14c0332392 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 14:46:51 -0400 Subject: [PATCH 28/57] addresses: update utxo response format --- README.md | 70 +++++++++++++++++++++++++++++++++--------------- lib/addresses.js | 30 ++++++++++++--------- 2 files changed, 67 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 4f300fc..5597b25 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,37 @@ The API endpoints will be available by default at: `http://localhost:3001/insigh ## Prerequisites -- [Bitcore Node 0.2.x](https://github.com/bitpay/bitcore-node) +- [Bitcore Node 3.x](https://github.com/bitpay/bitcore-node) -**Note:** You can use an existing Bitcoin data directory, however `txindex` needs to be set to true in `bitcoin.conf`. +**Note:** You can use an existing Bitcoin data directory, however `txindex`, `addressindex`, `timestampindex` and `spentindex` needs to be set to true in `bitcoin.conf`, as well as a few other additional fields. + +## Notes on Upgrading from v0.3 + +The unspent outputs format now has `satoshis` and `height`: +``` +[ + { + "address":"mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "txid":"d5f8a96faccf79d4c087fa217627bb1120e83f8ea1a7d84b1de4277ead9bbac1", + "vout":0, + "scriptPubKey":"76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", + "amount":0.000006, + "satoshis":600, + "confirmations":0, + "ts":1461349425 + }, + { + "address": "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "txid": "bc9df3b92120feaee4edc80963d8ed59d6a78ea0defef3ec3cb374f2015bfc6e", + "vout": 1, + "scriptPubKey": "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", + "amount": 0.12345678, + "satoshis: 12345678, + "height": 300001 + } +] +``` +The `timestamp` property will only be set for unconfirmed transactions and `height` can be used for determining block order. The `confirmationsFromCache` is nolonger set or necessary, confirmation count is only cached for the time between blocks. ## Notes on Upgrading from v0.2 @@ -95,25 +123,25 @@ The response contains the value in Satoshis. Sample return: ``` json [ - { - "address": "n2PuaAguxZqLddRbTnAoAuwKYgN2w2hZk7", - "txid": "dbfdc2a0d22a8282c4e7be0452d595695f3a39173bed4f48e590877382b112fc", - "vout": 0, - "ts": 1401276201, - "scriptPubKey": "76a914e50575162795cd77366fb80d728e3216bd52deac88ac", - "amount": 0.001, - "confirmations": 3 - }, - { - "address": "n2PuaAguxZqLddRbTnAoAuwKYgN2w2hZk7", - "txid": "e2b82af55d64f12fd0dd075d0922ee7d6a300f58fe60a23cbb5831b31d1d58b4", - "vout": 0, - "ts": 1401226410, - "scriptPubKey": "76a914e50575162795cd77366fb80d728e3216bd52deac88ac", - "amount": 0.001, - "confirmation": 6, - "confirmationsFromCache": true - } + { + "address":"mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "txid":"d5f8a96faccf79d4c087fa217627bb1120e83f8ea1a7d84b1de4277ead9bbac1", + "vout":0, + "scriptPubKey":"76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", + "amount":0.000006, + "satoshis":600, + "confirmations":0, + "ts":1461349425 + }, + { + "address": "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "txid": "bc9df3b92120feaee4edc80963d8ed59d6a78ea0defef3ec3cb374f2015bfc6e", + "vout": 1, + "scriptPubKey": "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", + "amount": 0.12345678, + "satoshis: 12345678, + "height": 300001 + } ] ``` diff --git a/lib/addresses.js b/lib/addresses.js index e30a7fb..e83ab68 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -128,7 +128,6 @@ AddressController.prototype.utxo = function(req, res) { AddressController.prototype.multiutxo = function(req, res) { var self = this; - this.node.getAddressUnspentOutputs(req.addrs, true, function(err, utxos) { if(err && err.code === -5) { return res.jsonp([]); @@ -140,18 +139,25 @@ AddressController.prototype.multiutxo = function(req, res) { }); }; -AddressController.prototype.transformUtxo = function(utxo) { - return { - address: utxo.address, - txid: utxo.txid, - vout: utxo.outputIndex, - height: utxo.height, - ts: utxo.timestamp ? parseInt(utxo.timestamp) : Date.now(), - scriptPubKey: utxo.script, - amount: utxo.satoshis / 1e8, - satoshis: utxo.satoshis, - confirmations: this.node.services.bitcoind.height - utxo.height + 1 +AddressController.prototype.transformUtxo = function(utxoArg) { + var utxo = { + address: utxoArg.address, + txid: utxoArg.txid, + vout: utxoArg.outputIndex, + scriptPubKey: utxoArg.script, + amount: utxoArg.satoshis / 1e8, + satoshis: utxoArg.satoshis }; + if (utxoArg.height && utxoArg.height > 0) { + utxo.height = utxoArg.height; + utxo.confirmations = this.node.services.bitcoind.height - utxoArg.height + 1; + } else { + utxo.confirmations = 0; + } + if (utxoArg.timestamp) { + utxo.ts = utxoArg.timestamp; + } + return utxo; }; AddressController.prototype.multitxs = function(req, res, next) { From 36ad6ebbbea9303568d09d392ec6413ae1d62d47 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 15:12:18 -0400 Subject: [PATCH 29/57] docs: include rawblock in readme --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5597b25..9b7e2eb 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ The API endpoints will be available by default at: `http://localhost:3001/insigh ## Notes on Upgrading from v0.3 The unspent outputs format now has `satoshis` and `height`: -``` +```json [ { "address":"mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", @@ -50,6 +50,15 @@ The unspent outputs format now has `satoshis` and `height`: ``` The `timestamp` property will only be set for unconfirmed transactions and `height` can be used for determining block order. The `confirmationsFromCache` is nolonger set or necessary, confirmation count is only cached for the time between blocks. +There is a new `GET` endpoint or raw blocks at `/rawblock/`, where `blockArg` can be hash or height: + +Response format: +```json +{ + "rawblock": "blockhexstring.." +} +``` + ## Notes on Upgrading from v0.2 Some of the fields and methods are not supported: From bc9bb10ea7dc478e8495f578b3c960dec9178d8b Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 15:15:07 -0400 Subject: [PATCH 30/57] docs: remove json markdown --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9b7e2eb..293eb6f 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ The API endpoints will be available by default at: `http://localhost:3001/insigh ## Notes on Upgrading from v0.3 The unspent outputs format now has `satoshis` and `height`: -```json +``` [ { "address":"mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", @@ -53,7 +53,7 @@ The `timestamp` property will only be set for unconfirmed transactions and `heig There is a new `GET` endpoint or raw blocks at `/rawblock/`, where `blockArg` can be hash or height: Response format: -```json +``` { "rawblock": "blockhexstring.." } @@ -130,7 +130,7 @@ The response contains the value in Satoshis. /insight-api/addr/[:addr]/utxo[?noCache=1] ``` Sample return: -``` json +``` [ { "address":"mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", From 465b14a0dd862e9030a183aceb3da7a77bc29314 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 15:20:54 -0400 Subject: [PATCH 31/57] docs: fix formatting in readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 293eb6f..60e2855 100644 --- a/README.md +++ b/README.md @@ -263,7 +263,7 @@ POST response: /insight-api/sync ``` -### Live Network P2P Data Sync Status (Bitcoind runs in the same process) +### Live Network P2P Data Sync Status ``` /insight-api/peer ``` @@ -292,7 +292,7 @@ The web socket API is served using [socket.io](http://socket.io). The following are the events published by insight: -'tx': new transaction received from network. This event is published in the 'inv' room. Data will be a app/models/Transaction object. +`tx`: new transaction received from network. This event is published in the 'inv' room. Data will be a app/models/Transaction object. Sample output: ``` { @@ -303,7 +303,7 @@ Sample output: ``` -'block': new block received from network. This event is published in the 'inv' room. Data will be a app/models/Block object. +`block`: new block received from network. This event is published in the `inv` room. Data will be a app/models/Block object. Sample output: ``` { @@ -313,9 +313,9 @@ Sample output: } ``` -'': new transaction concerning received from network. This event is published in the '' room. +``: new transaction concerning received from network. This event is published in the `` room. -'status': every 1% increment on the sync task, this event will be triggered. This event is published in the 'sync' room. +`status`: every 1% increment on the sync task, this event will be triggered. This event is published in the `sync` room. Sample output: ``` From 95b2a04937283b8aa54a0ff2db6a2567638ef794 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 15:26:20 -0400 Subject: [PATCH 32/57] docs: add rawblock endpoint to docs --- README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60e2855..89e6538 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ There is a new `GET` endpoint or raw blocks at `/rawblock/`, where `bl Response format: ``` { - "rawblock": "blockhexstring.." + "rawblock": "blockhexstring..." } ``` @@ -98,10 +98,26 @@ Get block hash by height ``` This would return: ``` -{"blockHash":"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"} +{ + "blockHash":"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" +} ``` which is the hash of the Genesis block (0 height) + +### Raw Block +``` + /insight-api/rawblock/[:blockHash] + /insight-api/rawblock/[:blockHeight] +``` + +This would return: +``` +{ + "rawblock":"blockhexstring..." +} +``` + ### Transaction ``` /insight-api/tx/[:txid] From 2efa5562bec8f90557c2ff2e23bd711cbcab3f7b Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 15:27:57 -0400 Subject: [PATCH 33/57] docs: remove nolonger relevant noCache query from readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 89e6538..20a6d69 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ This would return: ### Address ``` - /insight-api/addr/[:addr][?noTxList=1&noCache=1] + /insight-api/addr/[:addr][?noTxList=1] /insight-api/addr/mmvP3mTe53qxHdPqXEvdu8WdC7GfQ2vmx5?noTxList=1 ``` @@ -143,7 +143,7 @@ The response contains the value in Satoshis. ### Unspent Outputs ``` - /insight-api/addr/[:addr]/utxo[?noCache=1] + /insight-api/addr/[:addr]/utxo ``` Sample return: ``` From 203df0d736a1e67fddae312aaf4a484a618100a5 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 15:30:58 -0400 Subject: [PATCH 34/57] docs: fix confirmations in example for utxo --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 20a6d69..c21f006 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ The unspent outputs format now has `satoshis` and `height`: "scriptPubKey": "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", "amount": 0.12345678, "satoshis: 12345678, + "confirmations": 1, "height": 300001 } ] @@ -165,6 +166,7 @@ Sample return: "scriptPubKey": "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", "amount": 0.12345678, "satoshis: 12345678, + "confirmations": 1, "height": 300001 } ] From f890daa1085b5b05d2ca4f9c19568fbfbd32d19b Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 17:23:13 -0400 Subject: [PATCH 35/57] docs: update readme to include blocks endpoint --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index c21f006..768127e 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,42 @@ This would return: } ``` +### Block Summaries + +Get block summaries by date: +``` + /insight-api/blocks?limit=3&blockDate=2016-04-22 +``` + +Example response: +``` +{ + "blocks": [ + { + "height": 408495, + "size": 989237, + "hash": "00000000000000000108a1f4d4db839702d72f16561b1154600a26c453ecb378", + "time": 1461360083, + "txlength": 1695, + "poolInfo": { + "poolName": "BTCC Pool", + "url": "https://pool.btcc.com/" + } + } + ], + "length": 1, + "pagination": { + "next": "2016-04-23", + "prev": "2016-04-21", + "currentTs": 1461369599, + "current": "2016-04-22", + "isToday": true, + "more": true, + "moreTs": 1461369600 + } +} +``` + ### Transaction ``` /insight-api/tx/[:txid] From c83842eb6007b8fa66d623ebb203d7c5b4a61067 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 22 Apr 2016 17:29:26 -0400 Subject: [PATCH 36/57] addresses: parseInt from and to --- lib/addresses.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index e83ab68..62c4cdc 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -164,10 +164,10 @@ AddressController.prototype.multitxs = function(req, res, next) { var self = this; var options = { - from: req.query.from || req.body.from || 0 + from: parseInt(req.query.from) || parseInt(req.body.from) || 0 }; - options.to = req.query.to || req.body.to || options.from + 10; + options.to = parseInt(req.query.to) || parseInt(req.body.to) || parseInt(options.from) + 10; self.node.getAddressHistory(req.addrs, options, function(err, result) { if(err) { From 87643fba45d667d46185058912247a984b4b77d2 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 25 Apr 2016 12:42:45 -0400 Subject: [PATCH 37/57] docs: update upgrade notes with additional differences --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 768127e..1335aaa 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,13 @@ Response format: } ``` +Some additional general notes: +- The response for the `/sync` endpoint does not include `startTs` and `endTs` as the sync is no longer relevant as indexes are built in bitcoind. +- The endpoint for `/peer` is no longer relevant connection to bitcoind is via ZMQ. +- The list of txids in an address summary does not include orphaned transactions. +- `/tx` endpoint results will now include block height, and spentTx related fields will be set to `null` if unspent. +- `/block` endpoint results does not include `confirmations` and will include `poolInfo`. + ## Notes on Upgrading from v0.2 Some of the fields and methods are not supported: From b446f6733c3f71ea4a983d10e5f4ce4f15f97c68 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 9 May 2016 17:54:08 -0400 Subject: [PATCH 38/57] transaction: handle error --- lib/transactions.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/transactions.js b/lib/transactions.js index c63d2b5..5682ddf 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -231,6 +231,9 @@ TxController.prototype.list = function(req, res) { } self.node.services.bitcoind.getBlockHeader(block.hash, function(err, blockInfo) { + if (err) { + return common.handleErrors(err, res); + } var totalTxs = block.transactions.length; var txs; From 4e54d195b947e1ac023d365e967b572b453c954b Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 9 May 2016 17:54:57 -0400 Subject: [PATCH 39/57] blocks: add configurable option for caches --- lib/blocks.js | 11 +++++++---- lib/index.js | 10 +++++++++- test/blocks.js | 8 ++++---- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 71eb7de..f99721f 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -8,13 +8,13 @@ var BN = bitcore.crypto.BN; var LRU = require('lru-cache'); -function BlockController(node) { +function BlockController(options) { var self = this; - this.node = node; + this.node = options.node; - this.blockSummaryCache = LRU(1000000); + this.blockSummaryCache = LRU(options.blockSummaryCacheSize || BlockController.DEFAULT_BLOCKSUMMARY_CACHE_SIZE); this.blockCacheConfirmations = 6; - this.blockCache = LRU(1000); + this.blockCache = LRU(options.blockCacheSize || BlockController.DEFAULT_BLOCK_CACHE_SIZE); this.poolStrings = {}; pools.forEach(function(pool) { @@ -29,6 +29,9 @@ function BlockController(node) { var BLOCK_LIMIT = 200; +BlockController.DEFAULT_BLOCKSUMMARY_CACHE_SIZE = 1000000; +BlockController.DEFAULT_BLOCK_CACHE_SIZE = 1000; + /** * Find block by hash ... */ diff --git a/lib/index.js b/lib/index.js index 0e02cfa..ede8025 100644 --- a/lib/index.js +++ b/lib/index.js @@ -46,6 +46,9 @@ var InsightAPI = function(options) { this.cacheShortSeconds = options.cacheShortSeconds; this.cacheLongSeconds = options.cacheLongSeconds; + this.blockSummaryCacheSize = options.blockSummaryCacheSize || BlockController.DEFAULT_BLOCKSUMMARY_CACHE_SIZE; + this.blockCacheSize = options.blockCacheSize || BlockController.DEFAULT_BLOCK_CACHE_SIZE; + if (!_.isUndefined(options.routePrefix)) { this.routePrefix = options.routePrefix; } else { @@ -131,7 +134,12 @@ InsightAPI.prototype.setupRoutes = function(app) { }); //Block routes - var blocks = new BlockController(this.node); + var blockOptions = { + node: this.node, + blockSummaryCacheSize: this.blockSummaryCacheSize, + blockCacheSize: this.blockCacheSize + }; + var blocks = new BlockController(blockOptions); app.get('/blocks', this.cacheShort(), blocks.list.bind(blocks)); diff --git a/test/blocks.js b/test/blocks.js index d670597..b71bd45 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -83,7 +83,7 @@ describe('Blocks', function() { }; it('block data should be correct', function(done) { - var controller = new BlockController(node); + var controller = new BlockController({node: node}); var req = {}; var res = {}; var next = function() { @@ -110,7 +110,7 @@ describe('Blocks', function() { } } }; - var controller = new BlockController(node); + var controller = new BlockController({node: node}); var req = {}; var res = {}; var next = function() { @@ -187,7 +187,7 @@ describe('Blocks', function() { }; it('should have correct data', function(done) { - var blocks = new BlockController(node); + var blocks = new BlockController({node: node}); var req = { query: { @@ -219,7 +219,7 @@ describe('Blocks', function() { }; it('should have correct data', function(done) { - var blocks = new BlockController(node); + var blocks = new BlockController({node: node}); var insight = { 'blockHash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7' From 29e96e83aeeca13ec3b089ad44e990d52ae72b61 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 10 May 2016 13:52:01 -0400 Subject: [PATCH 40/57] address: pass "from" and "to" options --- lib/addresses.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/addresses.js b/lib/addresses.js index 62c4cdc..84129a4 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -15,6 +15,11 @@ AddressController.prototype.show = function(req, res) { noTxList: parseInt(req.query.noTxList) }; + if (req.query.from && req.query.to) { + options.from = parseInt(req.query.from); + options.to = parseInt(req.query.to); + } + this.getAddressSummary(req.addr, options, function(err, data) { if(err) { return common.handleErrors(err, res); From 0ba78e7180b3c1a459065d76f54c7a2ed0a28c38 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 10 May 2016 15:57:38 -0400 Subject: [PATCH 41/57] docs: update documentation with address endpoint query optinos --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1335aaa..d1526cf 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,15 @@ Response format: } ``` +There are a few changes to the `GET` endpoint for `/addr/[:address]`: + +- The list of txids in an address summary does not include orphaned transactions +- The list of txids will be limited at 1000 txids +- There are two new query options "from" and "to" for pagination of the txids (e.g. `/addr/[:address]?from=1000&to=2000`) + Some additional general notes: - The response for the `/sync` endpoint does not include `startTs` and `endTs` as the sync is no longer relevant as indexes are built in bitcoind. - The endpoint for `/peer` is no longer relevant connection to bitcoind is via ZMQ. -- The list of txids in an address summary does not include orphaned transactions. - `/tx` endpoint results will now include block height, and spentTx related fields will be set to `null` if unspent. - `/block` endpoint results does not include `confirmations` and will include `poolInfo`. @@ -172,8 +177,9 @@ Example response: ### Address ``` - /insight-api/addr/[:addr][?noTxList=1] + /insight-api/addr/[:addr][?noTxList=1][&from=&to=] /insight-api/addr/mmvP3mTe53qxHdPqXEvdu8WdC7GfQ2vmx5?noTxList=1 + /insight-api/addr/mmvP3mTe53qxHdPqXEvdu8WdC7GfQ2vmx5?from=1000&to=2000 ``` ### Address Properties From 310dd99086de87d4a5873bc1f66bd9cd7a47cbce Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 10 May 2016 16:24:37 -0400 Subject: [PATCH 42/57] blocks: rename moreTs -> moreTimestamp for clarity --- lib/blocks.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index f99721f..27403ae 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -147,12 +147,12 @@ BlockController.prototype.blockIndex = function(req, res, next, height) { }); }; -BlockController.prototype._getBlockSummary = function(hash, moreTs, next) { +BlockController.prototype._getBlockSummary = function(hash, moreTimestamp, next) { var self = this; function finish(result) { - if (moreTs > result.time) { - moreTs = result.time; + if (moreTimestamp > result.time) { + moreTimestamp = result.time; } return next(null, result); } @@ -236,7 +236,7 @@ BlockController.prototype.list = function(req, res) { var next = lte ? this.formatTimestamp(new Date(lte * 1000)) : null; var limit = parseInt(req.query.limit || BLOCK_LIMIT); var more = false; - var moreTs = lte; + var moreTimestamp = lte; self.node.services.bitcoind.getBlockHashesByTimestamp(lte, gte, function(err, hashes) { if(err) { @@ -253,7 +253,7 @@ BlockController.prototype.list = function(req, res) { async.mapSeries( hashes, function(hash, next) { - self._getBlockSummary(hash, moreTs, next); + self._getBlockSummary(hash, moreTimestamp, next); }, function(err, blocks) { if(err) { @@ -278,7 +278,7 @@ BlockController.prototype.list = function(req, res) { }; if(more) { - data.pagination.moreTs = moreTs; + data.pagination.moreTs = moreTimestamp; } res.jsonp(data); From 7973e2398a63f8122ecddaaae56dad72365a5b2b Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 10 May 2016 16:50:28 -0400 Subject: [PATCH 43/57] blocks: switch to use req.param so that the last argument is the next callback --- lib/blocks.js | 10 ++++++---- test/blocks.js | 28 ++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 27403ae..62c8e43 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -35,9 +35,9 @@ BlockController.DEFAULT_BLOCK_CACHE_SIZE = 1000; /** * Find block by hash ... */ -BlockController.prototype.block = function(req, res, next, hash) { +BlockController.prototype.block = function(req, res, next) { var self = this; - + var hash = req.params.blockHash; var blockCached = self.blockCache.get(hash); if (blockCached) { @@ -69,8 +69,9 @@ BlockController.prototype.block = function(req, res, next, hash) { /** * Find rawblock by hash and height... */ -BlockController.prototype.rawBlock = function(req, res, next, blockArg) { +BlockController.prototype.rawBlock = function(req, res, next) { var self = this; + var blockArg = req.params.blockArg; self.node.getRawBlock(blockArg, function(err, blockBuffer) { if(err && err.code === -5) { @@ -136,7 +137,8 @@ BlockController.prototype.showRaw = function(req, res) { } }; -BlockController.prototype.blockIndex = function(req, res, next, height) { +BlockController.prototype.blockIndex = function(req, res) { + var height = req.params.height; this.node.services.bitcoind.getBlockHeader(parseInt(height), function(err, info) { if (err) { return common.handleErrors(err, res); diff --git a/test/blocks.js b/test/blocks.js index b71bd45..2836d73 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -84,7 +84,11 @@ describe('Blocks', function() { it('block data should be correct', function(done) { var controller = new BlockController({node: node}); - var req = {}; + var req = { + params: { + blockHash: hash + } + }; var res = {}; var next = function() { should.exist(req.block); @@ -95,7 +99,7 @@ describe('Blocks', function() { var hash = '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'; - controller.block(req, res, next, hash); + controller.block(req, res, next); }); it('block pool info should be correct', function(done) { @@ -111,7 +115,11 @@ describe('Blocks', function() { } }; var controller = new BlockController({node: node}); - var req = {}; + var req = { + params: { + blockHash: hash + } + }; var res = {}; var next = function() { should.exist(req.block); @@ -123,7 +131,7 @@ describe('Blocks', function() { var hash = '000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4'; - controller.block(req, res, next, hash); + controller.block(req, res, next); }); }); @@ -225,17 +233,21 @@ describe('Blocks', function() { 'blockHash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7' }; - var req = {}; + var height = 533974; + + var req = { + params: { + height: height + } + }; var res = { jsonp: function(data) { should(data).eql(insight); done(); } }; - var next = function() {}; - var height = 533974; - blocks.blockIndex(req, res, next, height); + blocks.blockIndex(req, res); }); }); From 98d5314ef25e886ea51677c741eb79d627d6f806 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 10 May 2016 16:55:16 -0400 Subject: [PATCH 44/57] transactions: switch to use req.param so that the last argument is the next callback --- lib/transactions.js | 7 ++++--- test/transactions.js | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/transactions.js b/lib/transactions.js index 5682ddf..9765ede 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -21,8 +21,9 @@ TxController.prototype.show = function(req, res) { /** * Find transaction by hash ... */ -TxController.prototype.transaction = function(req, res, next, txid) { +TxController.prototype.transaction = function(req, res, next) { var self = this; + var txid = req.params.txid; this.node.getTransactionWithBlockInfo(txid, function(err, transaction) { if (err && err.code === -5) { @@ -189,8 +190,8 @@ TxController.prototype.transformInvTransaction = function(transaction) { return transformed; }; -TxController.prototype.rawTransaction = function(req, res, next, txid) { - var self = this; +TxController.prototype.rawTransaction = function(req, res, next) { + var txid = req.params.txid; this.node.getTransaction(txid, function(err, transaction) { if (err && err.code === -5) { diff --git a/test/transactions.js b/test/transactions.js index 75a7926..5758a3a 100644 --- a/test/transactions.js +++ b/test/transactions.js @@ -187,7 +187,11 @@ describe('Transactions', function() { }; var transactions = new TxController(node); - var req = {}; + var req = { + params: { + txid: txid + } + }; var res = {}; var next = function() { var merged = _.merge(req.transaction, todos); @@ -196,7 +200,7 @@ describe('Transactions', function() { }; var txid = 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0'; - transactions.transaction(req, res, next, txid); + transactions.transaction(req, res, next); }); }); @@ -849,13 +853,17 @@ describe('Transactions', function() { var transactions = new TxController(node); var res = {}; - var req = {}; + var req = { + params: { + txid: txid + } + }; var next = function() { should(req.rawTransaction.rawtx).eql(hex); done(); }; var txid = '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd'; - transactions.rawTransaction(req, res, next, txid); + transactions.rawTransaction(req, res, next); }); }); From ebcc3607c281839238007cebae0c15bff9d6af76 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 10 May 2016 17:40:07 -0400 Subject: [PATCH 45/57] ratelimiter: rename every to interval and add tests --- lib/ratelimiter.js | 17 +++--- test/ratelimeter.js | 139 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 test/ratelimeter.js diff --git a/lib/ratelimiter.js b/lib/ratelimiter.js index c4b2f66..d1cbe99 100644 --- a/lib/ratelimiter.js +++ b/lib/ratelimiter.js @@ -1,19 +1,20 @@ 'use strict'; -var THREE_HOURS = 3* 60 * 60 * 1000; +var THREE_HOURS = 3 * 60 * 60 * 1000; /** * A rate limiter to be used as an express middleware. * * @param {Object} options + * @param {Object} options.node - The bitcore node object * @param {Number} options.limit - Number of requests for normal rate limiter - * @param {Number} options.every - Interval of the normal rate limiter + * @param {Number} options.interval - Interval of the normal rate limiter * @param {Array} options.whitelist - IP addresses that should have whitelist rate limiting * @param {Array} options.blacklist - IP addresses that should be blacklist rate limiting * @param {Number} options.whitelistLimit - Number of requests for whitelisted clients - * @param {Number} options.whitelistEvery - Interval for whitelisted clients + * @param {Number} options.whitelistInterval - Interval for whitelisted clients * @param {Number} options.blacklistLimit - Number of requests for blacklisted clients - * @param {Number} options.blacklistEvery - Interval for blacklisted clients + * @param {Number} options.blacklistInterval - Interval for blacklisted clients */ function RateLimiter(options) { if (!(this instanceof RateLimiter)) { @@ -32,15 +33,15 @@ function RateLimiter(options) { this.config = { whitelist: { totalRequests: options.whitelistLimit || 3 * 60 * 60 * 10, // 108,000 - every: options.whitelistEvery || THREE_HOURS + interval: options.whitelistInterval || THREE_HOURS }, blacklist: { totalRequests: options.blacklistLimit || 0, - every: options.blacklistEvery || THREE_HOURS + interval: options.blacklistInterval || THREE_HOURS }, normal: { totalRequests: options.limit || 3 * 60 * 60, // 10,800 - every: options.every || THREE_HOURS + interval: options.interval || THREE_HOURS } }; @@ -117,7 +118,7 @@ RateLimiter.prototype.addClient = function(name) { visits: 1 }; - var resetTime = this.config[client.type].every; + var resetTime = this.config[client.type].interval; setTimeout(function() { delete self.clients[name]; diff --git a/test/ratelimeter.js b/test/ratelimeter.js new file mode 100644 index 0000000..3b2051f --- /dev/null +++ b/test/ratelimeter.js @@ -0,0 +1,139 @@ +'use strict'; + +var should = require('should'); +var sinon = require('sinon'); + +var RateLimiter = require('../lib/ratelimiter'); + +describe('RateLimiter', function() { + + describe('@constructor', function() { + it('will instantiate without options', function() { + var limiter = new RateLimiter(); + should.exist(limiter); + }); + it('will instantiate without new', function() { + /* jshint newcap:false */ + var limiter = RateLimiter(); + should.exist(limiter); + }); + it('will instantiate with options', function() { + var whitelist = []; + var blacklist = []; + var node = {}; + var limiter = new RateLimiter({ + node: node, + whitelist: whitelist, + blacklist: blacklist, + limit: 1, + interval: 1, + whitelistLimit: 1, + whitelistInterval: 1, + blacklistLimit: 1, + blacklistInterval: 1 + }); + should.exist(limiter); + should.exist(limiter.config); + should.exist(limiter.clients); + should.exist(limiter.node); + limiter.whitelist.should.equal(whitelist); + limiter.blacklist.should.equal(blacklist); + limiter.config.whitelist.totalRequests.should.equal(1); + limiter.config.whitelist.interval.should.equal(1); + limiter.config.blacklist.totalRequests.should.equal(1); + limiter.config.blacklist.interval.should.equal(1); + limiter.config.normal.interval.should.equal(1); + limiter.config.normal.totalRequests.should.equal(1); + }); + }); + + describe('#middleware', function() { + }); + + describe('#exceeded', function() { + it('should not be exceeded', function() { + var node = {}; + var limiter = new RateLimiter({node: node}); + var client = limiter.addClient('127.0.0.1'); + var exceeded = limiter.exceeded(client); + exceeded.should.equal(false); + }); + it('should be exceeded', function() { + var node = {}; + var limiter = new RateLimiter({node: node}); + var client = limiter.addClient('127.0.0.1'); + client.visits = 3 * 60 * 60 + 1; + var exceeded = limiter.exceeded(client); + exceeded.should.equal(true); + }); + it('should exclude whitelisted with no limit', function() { + var node = {}; + var limiter = new RateLimiter({ + whitelist: [ + '127.0.0.1' + ], + node: node, + whitelistLimit: -1 + }); + var client = limiter.addClient('127.0.0.1'); + client.visits = Infinity; + var exceeded = limiter.exceeded(client); + exceeded.should.equal(false); + }); + }); + + describe('#getClientName', function() { + it('should get client name from cloudflare header', function() { + var node = {}; + var limiter = new RateLimiter({node: node}); + var req = { + headers: { + 'cf-connecting-ip': '127.0.0.1' + } + }; + var name = limiter.getClientName(req); + name.should.equal('127.0.0.1'); + }); + it('should get client name from x forwarded header', function() { + var node = {}; + var limiter = new RateLimiter({node: node}); + var req = { + headers: { + 'x-forwarded-for': '127.0.0.1' + } + }; + var name = limiter.getClientName(req); + name.should.equal('127.0.0.1'); + }); + it('should get client name from connection remote address', function() { + var node = {}; + var limiter = new RateLimiter({node: node}); + var req = { + headers: {}, + connection: { + remoteAddress: '127.0.0.1' + } + }; + var name = limiter.getClientName(req); + name.should.equal('127.0.0.1'); + }); + }); + + describe('#addClient', function() { + var sandbox = sinon.sandbox.create(); + afterEach(function() { + sandbox.restore(); + }); + it('will remove client after interval', function() { + var THREE_HOURS_PLUS = 3 * 60 * 60 * 1000 + 1; + var clock = sandbox.useFakeTimers(); + var node = {}; + var limiter = new RateLimiter({node: node}); + limiter.addClient('127.0.0.1'); + should.exist(limiter.clients['127.0.0.1']); + clock.tick(THREE_HOURS_PLUS); + should.not.exist(limiter.clients['127.0.0.1']); + }); + }); + +}); From 351c315736306652410de63343d3c03fe9bd45de Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 10 May 2016 19:26:10 -0400 Subject: [PATCH 46/57] common: improve error logging --- lib/addresses.js | 22 +++++++++++++--------- lib/blocks.js | 24 +++++++++++++----------- lib/common.js | 17 +++++++++++------ lib/messages.js | 8 +++++--- lib/status.js | 14 ++++++++------ lib/transactions.js | 35 +++++++++++++++++++---------------- lib/utils.js | 5 +++-- test/blocks.js | 9 ++++++++- test/index.js | 36 ++++++++++++++++++++++++++++++------ 9 files changed, 110 insertions(+), 60 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index 84129a4..beae11f 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -1,16 +1,18 @@ 'use strict'; -var common = require('./common'); var bitcore = require('bitcore-lib'); var async = require('async'); var TxController = require('./transactions'); +var Common = require('./common'); function AddressController(node) { this.node = node; this.txController = new TxController(node); + this.common = new Common({log: this.node.log}); } AddressController.prototype.show = function(req, res) { + var self; var options = { noTxList: parseInt(req.query.noTxList) }; @@ -22,7 +24,7 @@ AddressController.prototype.show = function(req, res) { this.getAddressSummary(req.addr, options, function(err, data) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp(data); @@ -46,9 +48,10 @@ AddressController.prototype.unconfirmedBalance = function(req, res) { }; AddressController.prototype.addressSummarySubQuery = function(req, res, param) { + var self = this; this.getAddressSummary(req.addr, {}, function(err, data) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp(data[param]); @@ -97,8 +100,9 @@ AddressController.prototype.checkAddrs = function(req, res, next) { }; AddressController.prototype.check = function(req, res, next, addresses) { + var self = this; if(!addresses.length || !addresses[0]) { - return common.handleErrors({ + return self.common.handleErrors({ message: 'Must include address', code: 1 }, res); @@ -108,7 +112,7 @@ AddressController.prototype.check = function(req, res, next, addresses) { try { var a = new bitcore.Address(addresses[i]); } catch(e) { - return common.handleErrors({ + return self.common.handleErrors({ message: 'Invalid address: ' + e.message, code: 1 }, res); @@ -123,7 +127,7 @@ AddressController.prototype.utxo = function(req, res) { this.node.getAddressUnspentOutputs(req.addr, {}, function(err, utxos) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } else if (!utxos.length) { return res.jsonp([]); } @@ -137,7 +141,7 @@ AddressController.prototype.multiutxo = function(req, res) { if(err && err.code === -5) { return res.jsonp([]); } else if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp(utxos.map(self.transformUtxo.bind(self))); @@ -176,12 +180,12 @@ AddressController.prototype.multitxs = function(req, res, next) { self.node.getAddressHistory(req.addrs, options, function(err, result) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } self.transformAddressHistoryForMultiTxs(result.items, function(err, items) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp({ totalItems: result.totalCount, diff --git a/lib/blocks.js b/lib/blocks.js index 62c8e43..ff174cc 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -1,12 +1,11 @@ 'use strict'; -var common = require('./common'); var async = require('async'); var bitcore = require('bitcore-lib'); var pools = require('../pools.json'); var BN = bitcore.crypto.BN; var LRU = require('lru-cache'); - +var Common = require('./common'); function BlockController(options) { var self = this; @@ -25,6 +24,8 @@ function BlockController(options) { }; }); }); + + this.common = new Common({log: this.node.log}); } var BLOCK_LIMIT = 200; @@ -47,13 +48,13 @@ BlockController.prototype.block = function(req, res, next) { } else { self.node.getBlock(hash, function(err, block) { if(err && err.code === -5) { - return common.handleErrors(null, res); + return self.common.handleErrors(null, res); } else if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } self.node.services.bitcoind.getBlockHeader(hash, function(err, info) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } var blockResult = self.transformBlock(block, info); if (blockResult.confirmations >= self.blockCacheConfirmations) { @@ -75,9 +76,9 @@ BlockController.prototype.rawBlock = function(req, res, next) { self.node.getRawBlock(blockArg, function(err, blockBuffer) { if(err && err.code === -5) { - return common.handleErrors(null, res); + return self.common.handleErrors(null, res); } else if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } req.rawBlock = { rawblock: blockBuffer.toString('hex') @@ -138,10 +139,11 @@ BlockController.prototype.showRaw = function(req, res) { }; BlockController.prototype.blockIndex = function(req, res) { + var self = this; var height = req.params.height; this.node.services.bitcoind.getBlockHeader(parseInt(height), function(err, info) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp({ blockHash: info.hash @@ -221,7 +223,7 @@ BlockController.prototype.list = function(req, res) { dateStr = req.query.blockDate; var datePattern = /\d{4}-\d{2}-\d{2}/; if(!datePattern.test(dateStr)) { - return common.handleErrors(new Error('Please use yyyy-mm-dd format'), res); + return self.common.handleErrors(new Error('Please use yyyy-mm-dd format'), res); } isToday = dateStr === todayStr; @@ -242,7 +244,7 @@ BlockController.prototype.list = function(req, res) { self.node.services.bitcoind.getBlockHashesByTimestamp(lte, gte, function(err, hashes) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } hashes.reverse(); @@ -259,7 +261,7 @@ BlockController.prototype.list = function(req, res) { }, function(err, blocks) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } blocks.sort(function(a, b) { diff --git a/lib/common.js b/lib/common.js index d7fb9af..ea90111 100644 --- a/lib/common.js +++ b/lib/common.js @@ -1,19 +1,24 @@ 'use strict'; -exports.notReady = function (err, res, p) { +function Common(options) { + this.log = options.log; +} + +Common.prototype.notReady = function (err, res, p) { res.status(503).send('Server not yet ready. Sync Percentage:' + p); }; -exports.handleErrors = function (err, res) { +Common.prototype.handleErrors = function (err, res) { if (err) { if (err.code) { res.status(400).send(err.message + '. Code:' + err.code); - } - else { + } else { + this.log.error(err.stack); res.status(503).send(err.message); } - } - else { + } else { res.status(404).send('Not found'); } }; + +module.exports = Common; diff --git a/lib/messages.js b/lib/messages.js index 79b2ec5..ac7e573 100644 --- a/lib/messages.js +++ b/lib/messages.js @@ -3,18 +3,20 @@ var bitcore = require('bitcore-lib'); var _ = bitcore.deps._; var Message = require('bitcore-message'); -var common = require('./common'); +var Common = require('./common'); function MessagesController(node) { this.node = node; + this.common = new Common({log: this.node.log}); } MessagesController.prototype.verify = function(req, res) { + var self = this; var address = req.body.address || req.query.address; var signature = req.body.signature || req.query.signature; var message = req.body.message || req.query.message; if(_.isUndefined(address) || _.isUndefined(signature) || _.isUndefined(message)) { - return common.handleErrors({ + return self.common.handleErrors({ message: 'Missing parameters (expected "address", "signature" and "message")', code: 1 }, res); @@ -23,7 +25,7 @@ MessagesController.prototype.verify = function(req, res) { try { valid = new Message(message).verify(address, signature); } catch(err) { - return common.handleErrors({ + return self.common.handleErrors({ message: 'Unexpected error: ' + err.message, code: 1 }, res); diff --git a/lib/status.js b/lib/status.js index 1f850a6..bc4b7ad 100644 --- a/lib/status.js +++ b/lib/status.js @@ -1,19 +1,21 @@ 'use strict'; -var common = require('./common'); +var Common = require('./common'); function StatusController(node) { this.node = node; + this.common = new Common({log: this.node.log}); } StatusController.prototype.show = function(req, res) { + var self = this; var option = req.query.q; switch(option) { case 'getDifficulty': this.getDifficulty(function(err, result) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp(result); }); @@ -24,7 +26,7 @@ StatusController.prototype.show = function(req, res) { case 'getBestBlockHash': this.getBestBlockHash(function(err, result) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp(result); }); @@ -33,7 +35,7 @@ StatusController.prototype.show = function(req, res) { default: this.getInfo(function(err, result) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp({ info: result @@ -82,7 +84,7 @@ StatusController.prototype.sync = function(req, res) { this.node.services.bitcoind.isSynced(function(err, synced) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } if (synced) { status = 'finished'; @@ -90,7 +92,7 @@ StatusController.prototype.sync = function(req, res) { self.node.services.bitcoind.syncPercentage(function(err, percentage) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } var info = { status: status, diff --git a/lib/transactions.js b/lib/transactions.js index 9765ede..4ff3eeb 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -3,13 +3,14 @@ var bitcore = require('bitcore-lib'); var _ = bitcore.deps._; var $ = bitcore.util.preconditions; -var common = require('./common'); +var Common = require('./common'); var async = require('async'); var MAXINT = 0xffffffff; // Math.pow(2, 32) - 1; function TxController(node) { this.node = node; + this.common = new Common({log: this.node.log}); } TxController.prototype.show = function(req, res) { @@ -27,9 +28,9 @@ TxController.prototype.transaction = function(req, res, next) { this.node.getTransactionWithBlockInfo(txid, function(err, transaction) { if (err && err.code === -5) { - return common.handleErrors(null, res); + return self.common.handleErrors(null, res); } else if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } transaction.populateInputs(self.node.services.bitcoind, [], function(err) { @@ -41,7 +42,7 @@ TxController.prototype.transaction = function(req, res, next) { self.transformTransaction(transaction, function(err, transformedTransaction) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } req.transaction = transformedTransaction; next(); @@ -191,13 +192,14 @@ TxController.prototype.transformInvTransaction = function(transaction) { }; TxController.prototype.rawTransaction = function(req, res, next) { + var self = this; var txid = req.params.txid; this.node.getTransaction(txid, function(err, transaction) { if (err && err.code === -5) { - return common.handleErrors(null, res); + return self.common.handleErrors(null, res); } else if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } req.rawTransaction = { @@ -226,14 +228,14 @@ TxController.prototype.list = function(req, res) { if(blockHash) { self.node.getBlock(blockHash, function(err, block) { if(err && err.message === 'Block not found.') { - return common.handleErrors(null, res); + return self.common.handleErrors(null, res); } else if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } self.node.services.bitcoind.getBlockHeader(block.hash, function(err, blockInfo) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } var totalTxs = block.transactions.length; var txs; @@ -254,13 +256,13 @@ TxController.prototype.list = function(req, res) { // get previous outputs tx.populateInputs(self.node.services.bitcoind, [], function(err) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } // get spent info tx.populateSpentInfo(self.node.services.bitcoind, {}, function(err) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } self.transformTransaction(tx, next); }); @@ -268,7 +270,7 @@ TxController.prototype.list = function(req, res) { }); }, function(err, transformed) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp({ @@ -288,7 +290,7 @@ TxController.prototype.list = function(req, res) { self.node.getAddressHistory(address, options, function(err, result) { if(err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } var txs = result.items.map(function(info) { @@ -304,7 +306,7 @@ TxController.prototype.list = function(req, res) { }, function(err, transformed) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp({ pagesTotal: Math.ceil(result.totalCount / pageLength), @@ -314,15 +316,16 @@ TxController.prototype.list = function(req, res) { ); }); } else { - return common.handleErrors(new Error('Block hash or address expected'), res); + return self.common.handleErrors(new Error('Block hash or address expected'), res); } }; TxController.prototype.send = function(req, res) { + var self = this; this.node.sendTransaction(req.body.rawtx, function(err, txid) { if(err) { // TODO handle specific errors - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.json({'txid': txid}); diff --git a/lib/utils.js b/lib/utils.js index 1028fb5..e4ddeec 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -2,10 +2,11 @@ var _ = require('lodash'); var async = require('async'); -var common = require('./common'); +var Common = require('./common'); function UtilsController(node) { this.node = node; + this.common = new Common({log: this.node.log}); } UtilsController.prototype.estimateFee = function(req, res) { @@ -24,7 +25,7 @@ UtilsController.prototype.estimateFee = function(req, res) { }); }, function(err, result) { if (err) { - return common.handleErrors(err, res); + return self.common.handleErrors(err, res); } res.jsonp(_.zipObject(result)); }); diff --git a/test/blocks.js b/test/blocks.js index 2836d73..88073c9 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -72,6 +72,7 @@ describe('Blocks', function() { var bitcoreBlock = bitcore.Block.fromBuffer(new Buffer(blocks['0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'], 'hex')); var node = { + log: sinon.stub(), getBlock: sinon.stub().callsArgWith(1, null, bitcoreBlock), services: { bitcoind: { @@ -105,6 +106,7 @@ describe('Blocks', function() { it('block pool info should be correct', function(done) { var block = bitcore.Block.fromString(blocks['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4']); var node = { + log: sinon.stub(), getBlock: sinon.stub().callsArgWith(1, null, block), services: { bitcoind: { @@ -183,6 +185,7 @@ describe('Blocks', function() { '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7' ]; var node = { + log: sinon.stub(), services: { bitcoind: { getRawBlock: stub, @@ -217,6 +220,7 @@ describe('Blocks', function() { describe('/block-index/:height route', function() { var node = { + log: sinon.stub(), services: { bitcoind: { getBlockHeader: function(height, callback) { @@ -252,7 +256,10 @@ describe('Blocks', function() { }); describe('#getBlockReward', function() { - var blocks = new BlockController({}); + var node = { + log: sinon.stub() + }; + var blocks = new BlockController({node: node}); it('should give a block reward of 50 * 1e8 for block before first halvening', function() { blocks.getBlockReward(100000).should.equal(50 * 1e8); diff --git a/test/index.js b/test/index.js index 2d8e5da..4975877 100644 --- a/test/index.js +++ b/test/index.js @@ -7,8 +7,12 @@ var InsightAPI = require('../lib/index'); describe('Index', function() { describe('#cache', function() { it('will set cache control header', function(done) { + var node = { + log: sinon.stub() + }; var index = new InsightAPI({ - enableCache: true + enableCache: true, + node: node }); var req = {}; var res = { @@ -23,8 +27,12 @@ describe('Index', function() { }); }); it('will NOT set cache control header', function(done) { + var node = { + log: sinon.stub() + }; var index = new InsightAPI({ - enableCache: false + enableCache: false, + node: node }); var req = {}; var res = { @@ -39,9 +47,13 @@ describe('Index', function() { }); describe('#cacheShort', function() { it('will set SHORT cache control header', function(done) { + var node = { + log: sinon.stub() + }; var index = new InsightAPI({ enableCache: true, - cacheShortSeconds: 35 + cacheShortSeconds: 35, + node: node }); var req = {}; var res = { @@ -56,8 +68,12 @@ describe('Index', function() { }); }); it('will set SHORT DEFAULT cache control header', function(done) { + var node = { + log: sinon.stub() + }; var index = new InsightAPI({ - enableCache: true + enableCache: true, + node: node }); var req = {}; var res = { @@ -74,9 +90,13 @@ describe('Index', function() { }); describe('#cacheLong', function() { it('will set LONG cache control header', function(done) { + var node = { + log: sinon.stub() + }; var index = new InsightAPI({ enableCache: true, - cacheLongSeconds: 86400000 + cacheLongSeconds: 86400000, + node: node }); var req = {}; var res = { @@ -91,8 +111,12 @@ describe('Index', function() { }); }); it('will set LONG DEFAULT cache control header', function(done) { + var node = { + log: sinon.stub() + }; var index = new InsightAPI({ - enableCache: true + enableCache: true, + node: node }); var req = {}; var res = { From c6bd150bd99ecea07d2565196c10b9f1ab16390b Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 11 May 2016 11:54:08 -0400 Subject: [PATCH 47/57] blocks: camelCase adjustments for bitcore node --- lib/blocks.js | 4 ++-- test/blocks.js | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index ff174cc..f7f97ae 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -113,10 +113,10 @@ BlockController.prototype.transformBlock = function(block, info) { nonce: blockObj.header.nonce, bits: blockObj.header.bits.toString(16), difficulty: block.header.getDifficulty(), - chainwork: info.chainwork, + chainwork: info.chainWork, confirmations: info.confirmations, previousblockhash: this._normalizePrevHash(blockObj.header.prevHash), - nextblockhash: info.nextblockhash, + nextblockhash: info.nextHash, reward: this.getBlockReward(info.height) / 1e8, isMainChain: (info.confirmations !== -1), poolInfo: this.getPoolInfo(block) diff --git a/test/blocks.js b/test/blocks.js index 88073c9..f88cdec 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -11,34 +11,34 @@ var blocks = require('./data/blocks.json'); var blockIndexes = { '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7': { hash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - chainwork: '0000000000000000000000000000000000000000000000054626b1839ade284a', - previousblockhash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', - nextblockhash: '000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d', + chainWork: '0000000000000000000000000000000000000000000000054626b1839ade284a', + prevHash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + nextHash: '000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d', confirmations: 119, height: 533974 }, '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7': { hash: '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', - chainwork: '00000000000000000000000000000000000000000000000544ea52e1575ca753', - previousblockhash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', + chainWork: '00000000000000000000000000000000000000000000000544ea52e1575ca753', + prevHash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', confirmations: 119, height: 533951 }, '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441': { hash: '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441', - chainwork: '00000000000000000000000000000000000000000000000544ea52e0575ba752', - previousblockhash: '000000000001b9c41e6c4a7b81a068b50cf3f522ee4ac1e942e75ec16e090547', + chainWork: '00000000000000000000000000000000000000000000000544ea52e0575ba752', + prevHash: '000000000001b9c41e6c4a7b81a068b50cf3f522ee4ac1e942e75ec16e090547', height: 533950 }, '000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4': { hash: '000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4', - previousblockhash: '00000000000000000a9d74a7b527f7b995fc21ceae5aa21087b443469351a362', + prevHash: '00000000000000000a9d74a7b527f7b995fc21ceae5aa21087b443469351a362', height: 375493 }, 533974: { hash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - chainwork: '0000000000000000000000000000000000000000000000054626b1839ade284a', - previousblockhash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + chainWork: '0000000000000000000000000000000000000000000000054626b1839ade284a', + prevHash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', height: 533974 } }; @@ -85,6 +85,7 @@ describe('Blocks', function() { it('block data should be correct', function(done) { var controller = new BlockController({node: node}); + var hash = '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'; var req = { params: { blockHash: hash @@ -97,9 +98,6 @@ describe('Blocks', function() { should(block).eql(insight); done(); }; - - var hash = '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'; - controller.block(req, res, next); }); From 285e3550f5dd964502d00fe86069ea8f595cfd3c Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 11 May 2016 11:54:29 -0400 Subject: [PATCH 48/57] status: camelCase adjustments for bitcore node --- lib/status.js | 20 +++++++++++++++++++- test/status.js | 6 +++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/status.js b/lib/status.js index bc4b7ad..eb6029f 100644 --- a/lib/status.js +++ b/lib/status.js @@ -45,7 +45,25 @@ StatusController.prototype.show = function(req, res) { }; StatusController.prototype.getInfo = function(callback) { - this.node.services.bitcoind.getInfo(callback); + this.node.services.bitcoind.getInfo(function(err, result) { + if (err) { + return callback(err); + } + var info = { + version: result.version, + protocolversion: result.protocolVersion, + blocks: result.blocks, + timeoffset: result.timeOffset, + connections: result.connections, + proxy: result.proxy, + difficulty: result.difficulty, + testnet: result.testnet, + relayfee: result.relayFee, + errors: result.errors, + network: result.network + }; + callback(null, info); + }); }; StatusController.prototype.getLastBlockHash = function() { diff --git a/test/status.js b/test/status.js index 9c2119a..d65f78e 100644 --- a/test/status.js +++ b/test/status.js @@ -8,13 +8,13 @@ describe('Status', function() { describe('/status', function() { var info = { version: 110000, - protocolversion: 70002, + protocolVersion: 70002, blocks: 548645, - timeoffset: 0, + timeOffset: 0, connections: 8, difficulty: 21546.906405522557, testnet: true, - relayfee: 1000, + relayFee: 1000, errors: '' }; From 9eacb3dedc87c8b38c541045bba7afb005865ef8 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 11 May 2016 13:36:27 -0400 Subject: [PATCH 49/57] docs: add notes about block order sorting --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d1526cf..a5cdfaf 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,12 @@ Response format: There are a few changes to the `GET` endpoint for `/addr/[:address]`: - The list of txids in an address summary does not include orphaned transactions +- The txids will be sorted in block order - The list of txids will be limited at 1000 txids - There are two new query options "from" and "to" for pagination of the txids (e.g. `/addr/[:address]?from=1000&to=2000`) Some additional general notes: +- The transaction history for an address will be sorted in block order - The response for the `/sync` endpoint does not include `startTs` and `endTs` as the sync is no longer relevant as indexes are built in bitcoind. - The endpoint for `/peer` is no longer relevant connection to bitcoind is via ZMQ. - `/tx` endpoint results will now include block height, and spentTx related fields will be set to `null` if unspent. From ae9f6a2c2f05b546f8c6cd2258f2478b78528da0 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 11 May 2016 14:17:47 -0400 Subject: [PATCH 50/57] test: add ratelimiter middleware unit test --- test/ratelimeter.js | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/ratelimeter.js b/test/ratelimeter.js index 3b2051f..5053b21 100644 --- a/test/ratelimeter.js +++ b/test/ratelimeter.js @@ -48,6 +48,56 @@ describe('RateLimiter', function() { }); describe('#middleware', function() { + it('will set ratelimit headers', function(done) { + var limiter = new RateLimiter(); + var req = { + headers: { + 'cf-connecting-ip': '127.0.0.1' + } + }; + var setHeader = sinon.stub(); + var res = { + setHeader: setHeader + }; + limiter.middleware()(req, res, function() { + setHeader.callCount.should.equal(2); + setHeader.args[0][0].should.equal('X-RateLimit-Limit'); + setHeader.args[0][1].should.equal(10800); + setHeader.args[1][0].should.equal('X-RateLimit-Remaining'); + setHeader.args[1][1].should.equal(10799); + done(); + }); + }); + it('will give rate limit error', function() { + var node = { + log: { + warn: sinon.stub() + } + }; + var limiter = new RateLimiter({node: node}); + limiter.exceeded = sinon.stub().returns(true); + var req = { + headers: { + 'cf-connecting-ip': '127.0.0.1' + } + }; + var jsonp = sinon.stub(); + var status = sinon.stub().returns({ + jsonp: jsonp + }); + var res = { + status: status, + setHeader: sinon.stub() + }; + limiter.middleware()(req, res); + status.callCount.should.equal(1); + status.args[0][0].should.equal(429); + jsonp.callCount.should.equal(1); + jsonp.args[0][0].should.eql({ + status: 429, + error: 'Rate limit exceeded' + }); + }); }); describe('#exceeded', function() { From 0465179a93f37e17ee36fcefd0630aebcb7e1dc1 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 12 May 2016 18:08:13 -0400 Subject: [PATCH 51/57] transaction: switch to use bitcore node getDetailedTransaction --- lib/transactions.js | 173 ++++++++---------- test/addresses.js | 71 ++++---- test/transactions.js | 407 +++++++++++++++++++++++++++---------------- 3 files changed, 360 insertions(+), 291 deletions(-) diff --git a/lib/transactions.js b/lib/transactions.js index 4ff3eeb..9217800 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -26,81 +26,71 @@ TxController.prototype.transaction = function(req, res, next) { var self = this; var txid = req.params.txid; - this.node.getTransactionWithBlockInfo(txid, function(err, transaction) { + this.node.getDetailedTransaction(txid, function(err, transaction) { if (err && err.code === -5) { return self.common.handleErrors(null, res); } else if(err) { return self.common.handleErrors(err, res); } - transaction.populateInputs(self.node.services.bitcoind, [], function(err) { - if(err) { - return res.send({ - error: err.toString() - }); + self.transformTransaction(transaction, function(err, transformedTransaction) { + if (err) { + return self.common.handleErrors(err, res); } - - self.transformTransaction(transaction, function(err, transformedTransaction) { - if (err) { - return self.common.handleErrors(err, res); - } - req.transaction = transformedTransaction; - next(); - }); - + req.transaction = transformedTransaction; + next(); }); + }); }; TxController.prototype.transformTransaction = function(transaction, callback) { $.checkArgument(_.isFunction(callback)); - var self = this; - var txid = transaction.id; - var txObj = transaction.toObject(); var confirmations = 0; - if(transaction.__height >= 0) { - confirmations = this.node.services.bitcoind.height - transaction.__height + 1; + if(transaction.height >= 0) { + confirmations = this.node.services.bitcoind.height - transaction.height + 1; } var transformed = { - txid: txObj.hash, - version: txObj.version, - locktime: txObj.nLockTime + txid: transaction.hash, + version: transaction.version, + locktime: transaction.locktime }; - if(transaction.isCoinbase()) { + if(transaction.coinbase) { transformed.vin = [ { - coinbase: txObj.inputs[0].script, - sequence: txObj.inputs[0].sequenceNumber, + coinbase: transaction.inputs[0].script, + sequence: transaction.inputs[0].sequence, n: 0 } ]; } else { - transformed.vin = txObj.inputs.map(this.transformInput.bind(this)); + transformed.vin = transaction.inputs.map(this.transformInput.bind(this)); } transformed.vout = transaction.outputs.map(this.transformOutput.bind(this)); - transformed.blockhash = transaction.__blockHash; - transformed.blockheight = transaction.__height; + transformed.blockhash = transaction.blockHash; + transformed.blockheight = transaction.height; transformed.confirmations = confirmations; - var time = transaction.__timestamp ? transaction.__timestamp : Math.round(Date.now() / 1000); + // TODO consider mempool txs with receivedTime? + var time = transaction.blockTimestamp ? transaction.blockTimestamp : Math.round(Date.now() / 1000); transformed.time = time; if (transformed.confirmations) { transformed.blocktime = transformed.time; } - if(transaction.isCoinbase()) { + if(transaction.coinbase) { transformed.isCoinBase = true; } - transformed.valueOut = transaction.outputAmount / 1e8; - transformed.size = transaction.toBuffer().length; - if(transaction.hasAllUtxoInfo()) { - transformed.valueIn = transaction.inputAmount / 1e8; - transformed.fees = transaction.getFee() / 1e8; + transformed.valueOut = transaction.outputSatoshis / 1e8; + transformed.size = transaction.hex.length / 2; // in bytes + if (!transaction.coinbase) { + transformed.valueIn = transaction.inputSatoshis / 1e8; + transformed.fees = transaction.feeSatoshis / 1e8; } callback(null, transformed); @@ -108,27 +98,24 @@ TxController.prototype.transformTransaction = function(transaction, callback) { TxController.prototype.transformInput = function(input, index) { // Input scripts are validated and can be assumed to be valid - var script = new bitcore.Script(input.script); var transformed = { txid: input.prevTxId, vout: input.outputIndex, scriptSig: { - asm: script.toASM(), + asm: input.scriptAsm, hex: input.script }, - sequence: input.sequenceNumber, + sequence: input.sequence, n: index }; - if(input.output) { - transformed.addr = bitcore.Script(input.output.script).toAddress(this.node.network).toString(); - transformed.valueSat = input.output.satoshis; - transformed.value = input.output.satoshis / 1e8; - transformed.doubleSpentTxID = null; // TODO - //transformed.isConfirmed = null; // TODO - //transformed.confirmations = null; // TODO - //transformed.unconfirmedInput = null; // TODO - } + transformed.addr = input.address; + transformed.valueSat = input.satoshis; + transformed.value = input.satoshis / 1e8; + transformed.doubleSpentTxID = null; // TODO + //transformed.isConfirmed = null; // TODO + //transformed.confirmations = null; // TODO + //transformed.unconfirmedInput = null; // TODO return transformed; }; @@ -138,23 +125,20 @@ TxController.prototype.transformOutput = function(output, index) { value: (output.satoshis / 1e8).toFixed(8), n: index, scriptPubKey: { - hex: output._scriptBuffer.toString('hex'), + hex: output.script, + asm: output.scriptAsm //reqSigs: null, // TODO }, - spentTxId: output.__spentTxId || null, - spentIndex: _.isUndefined(output.__spentIndex) ? null : output.__spentIndex, - spentHeight: output.__spentHeight || null + spentTxId: output.spentTxId || null, + spentIndex: _.isUndefined(output.spentIndex) ? null : output.spentIndex, + spentHeight: output.spentHeight || null //spentTs: undefined // TODO }; - var script = output.script; - if (script) { - transformed.scriptPubKey.asm = script.toASM(); - var address = script.toAddress(this.node.network); - if (address) { - transformed.scriptPubKey.addresses = [address.toString()]; - transformed.scriptPubKey.type = address.type; - } + if (output.address) { + transformed.scriptPubKey.addresses = [output.address]; + var address = bitcore.Address(output.address); //TODO return type from bitcore-node + transformed.scriptPubKey.type = address.type; } return transformed; }; @@ -226,59 +210,40 @@ TxController.prototype.list = function(req, res) { var pagesTotal = 1; if(blockHash) { - self.node.getBlock(blockHash, function(err, block) { - if(err && err.message === 'Block not found.') { + self.node.getBlockOverview(blockHash, function(err, block) { + if(err && err.code === -5) { return self.common.handleErrors(null, res); } else if(err) { return self.common.handleErrors(err, res); } - self.node.services.bitcoind.getBlockHeader(block.hash, function(err, blockInfo) { - if (err) { + var totalTxs = block.txids.length; + var txids; + + if(!_.isUndefined(page)) { + var start = page * pageLength; + txids = block.txids.slice(start, start + pageLength); + pagesTotal = Math.ceil(totalTxs / pageLength); + } else { + txids = block.txids; + } + + async.mapSeries(txids, function(txid, next) { + self.node.getDetailedTransaction(txid, function(err, transaction) { + if (err) { + return next(err); + } + self.transformTransaction(transaction, next); + }); + }, function(err, transformed) { + if(err) { return self.common.handleErrors(err, res); } - var totalTxs = block.transactions.length; - var txs; - if(!_.isUndefined(page)) { - var start = page * pageLength; - txs = block.transactions.slice(start, start + pageLength); - pagesTotal = Math.ceil(totalTxs / pageLength); - } else { - txs = block.transactions; - } - - async.mapSeries(txs, function(tx, next) { - tx.__blockHash = block.hash; - tx.__height = blockInfo.height; - tx.__timestamp = block.header.time; - - // get previous outputs - tx.populateInputs(self.node.services.bitcoind, [], function(err) { - if(err) { - return self.common.handleErrors(err, res); - } - - // get spent info - tx.populateSpentInfo(self.node.services.bitcoind, {}, function(err) { - if (err) { - return self.common.handleErrors(err, res); - } - self.transformTransaction(tx, next); - }); - - }); - }, function(err, transformed) { - if(err) { - return self.common.handleErrors(err, res); - } - - res.jsonp({ - pagesTotal: pagesTotal, - txs: transformed - }); + res.jsonp({ + pagesTotal: pagesTotal, + txs: transformed }); - }); }); diff --git a/test/addresses.js b/test/addresses.js index b226f37..b8e5b23 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -91,53 +91,56 @@ var txinfos = { ] }; -var tx = bitcore.Transaction().fromObject({ - 'hash': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', - 'version': 1, - 'inputs': [ +var tx = { + height: 534181, + blockTimestamp: 1441116143, + blockHash: '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013', + hex: '0100000002f379708395d0a0357514205a3758a0317926428356e54a09089852fc6f7297ea010000008a473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964dffffffffb758ffd4c31693d9620f326385404530a079d5e60a90b94e46d3c2dbc29c0a98020000008a473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2ffffffff03605b0300000000001976a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac40992d03000000001976a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac256c0400000000001976a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac00000000', + hash: '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + version: 1, + inputSatoshis: 53839829, + outputSatoshis: 53829829, + feeSatoshis: 10000, + inputs: [ { - 'prevTxId': 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', - 'outputIndex': 1, - 'sequenceNumber': 4294967295, - 'script': '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', - 'scriptString': '71 0x3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 65 0x040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', - 'output': { - 'satoshis': 53540000, - 'script': '76a91454dcfbff9e109bf369e457f6b0f869f4e647076488ac' - } + address: 'moFfnRwt77pApKnnU6m5uocFaa43aAYpt5', + prevTxId: 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', + outputIndex: 1, + sequence: 4294967295, + script: '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + scriptAsm: '71 0x3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 65 0x040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + satoshis: 53540000, }, { - 'prevTxId': '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', - 'outputIndex': 2, - 'sequenceNumber': 4294967295, - 'script': '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', - 'scriptString': '71 0x3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 65 0x04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', - 'output': { - 'satoshis': 299829, - 'script': '76a914db731c9ebf3874d75ee26b9c19b692d278c283f788ac' - } + address: 'n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv', + prevTxId: '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', + outputIndex: 2, + sequence: 4294967295, + script: '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + scriptAsm: '71 0x3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 65 0x04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + satoshis: 299829, } ], - 'outputs': [ + outputs: [ { - 'satoshis': 220000, - 'script': '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac' + satoshis: 220000, + script: '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', + address: 'mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp' }, { - 'satoshis': 53320000, - 'script': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac' + satoshis: 53320000, + address: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', + script: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac' }, { - 'satoshis': 289829, - 'script': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac' + address: 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + satoshis: 289829, + script: '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac' } ], - 'nLockTime': 0 -}); + locktime: 0 +}; -tx.__height = 534181; -tx.__timestamp = 1441116143; -tx.__blockHash = '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013'; var txinfos2 = { totalCount: 1, items: [ diff --git a/test/transactions.js b/test/transactions.js index 5758a3a..9370934 100644 --- a/test/transactions.js +++ b/test/transactions.js @@ -94,44 +94,56 @@ describe('Transactions', function() { 'fees': 0.0003 }; - var bitcoreTxObj = { - 'hash': 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', - 'version': 1, - 'inputs': [ + var spentTxId = '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec'; + var spentIndex = 1; + var detailedTransaction = { + hex: '7b5485d3628922f004f470f497f6a83f6df4df347e1bce15831a964623f8072b565f7c7bc5dcbc717c6e2a2301a2f6b4a19e65042ad88c9f5d037628de38603c4f137f625e135691e2bd0169cab74e1368abe858f3c3d116e9d13c4c85ead129d9edf0245a3fb1b35561bd230607dca0dcaf3cffc735a3982d8384a1ecc5d622a7bb4db8b5d47d061701978b1f45e2e39946d66c3394f8a20b8ac8c931a6786f761da2d0f3fa2c7c93edee9f2a94de7c47510498767c3d87afe68815bd6058710bf5d8c850a5d20fc217943d9c00da58a4908d92a0912578247746f2086e54cb7b81b6a9e3cc1741457e956d41bdeaae06c441db96ec39a2d17147dd8f468eeaeaaa78dc2e53d66188a791c46b2a4965639ad72a2b90ee52786e36db1a8cf924346b105a40b41a3027dae657782ef7e8b56d6da86062184cb5366d4886cd2ce27471d9d62d1df447f2e5a9641e1f8d1f2b628054d3bd915bf7932bcec6f2dd4965e2406b1dba445b5493ee475757de332618220318dd806b880a7364370c5c0c3b736a653f97b2901fdb5cf4b5b2230b09b2d7bd324a392633d51c598765f9bd286421239a1f25db34a9a61f645eb601e59f10fc1b', + hash: 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + version: 1, + blockHash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + height: 533974, + blockTimestamp: 1440987503, + inputSatoshis: 34955390, + outputSatoshis: 34925390, + feeSatoshis: 30000, + inputs: [ { - 'prevTxId': '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', - 'outputIndex': 0, - 'sequenceNumber': 4294967295, - 'script': '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - 'scriptString': '72 0x30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 65 0x04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - 'output': { - 'satoshis': 18535505, - 'script': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac' - } + address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + prevTxId: '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', + outputIndex: 0, + sequence: 4294967295, + script: '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + scriptAsm: '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + satoshis: 18535505, }, { - 'prevTxId': 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', - 'outputIndex': 0, - 'sequenceNumber': 4294967295, - 'script': '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - 'scriptString': '71 0x30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 65 0x04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', - 'output': { - 'satoshis': 16419885, - 'script': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac' - } + address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + prevTxId: 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', + outputIndex: 0, + sequence: 4294967295, + script: '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + scriptAsm: '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + satoshis: 16419885, } ], - 'outputs': [ + outputs: [ { - 'satoshis': 21247964, - 'script': '76a9144b7b335f978f130269fe661423258ae9642df8a188ac' + satoshis: 21247964, + script: '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', + scriptAsm: 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', + address: 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X' }, { - 'satoshis': 13677426, - 'script': '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac' + address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + satoshis: 13677426, + scriptAsm: 'OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG', + script: '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', + spentTxId: spentTxId, + spentIndex: spentIndex, + spentHeight: 10 } ], - 'nLockTime': 0 + locktime: 0 }; var todos = { @@ -162,22 +174,8 @@ describe('Transactions', function() { ] }; - var spentTxId = '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec'; - var spentIndex = 1; - - var bitcoreTx = bitcore.Transaction(bitcoreTxObj); - bitcoreTx.__blockHash = '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'; - bitcoreTx.__height = 533974; - bitcoreTx.__timestamp = 1440987503; - bitcoreTx.populateInputs = sinon.stub().callsArg(2); - bitcoreTx.toObject = sinon.stub().returns(bitcoreTxObj); - - bitcoreTx.outputs[1].__spentTxId = spentTxId; - bitcoreTx.outputs[1].__spentIndex = spentIndex; - bitcoreTx.outputs[1].__spentHeight = 10; - var node = { - getTransactionWithBlockInfo: sinon.stub().callsArgWith(1, null, bitcoreTx), + getDetailedTransaction: sinon.stub().callsArgWith(1, null, detailedTransaction), services: { bitcoind: { height: 534203 @@ -187,6 +185,7 @@ describe('Transactions', function() { }; var transactions = new TxController(node); + var txid = 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0'; var req = { params: { txid: txid @@ -198,7 +197,6 @@ describe('Transactions', function() { should(merged).eql(insight); done(); }; - var txid = 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0'; transactions.transaction(req, res, next); }); @@ -210,72 +208,162 @@ describe('Transactions', function() { sandbox.restore(); }); it('by block hash', function(done) { - var blockHex = '07000020a491892cca9f143f7f00b8d65bbce0204bb32e17e914325fa5010000000000003e28f0519ecf01f7f01ea8da61084b2e4741a18ce1f3738117b84458353764b06fb9e35567f20c1a78eb626f0301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac000000000100000002ad5a14ae9d0f3221b790c4fc590fddceea1456e5692d8c4bf1ff7175f2b0c987000000008b4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff9621ac65bc22ea593ca9a61a8d63e461bf3d3f277989df5d3bd33ddfae0aa1d8000000008a4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff02dc374401000000001976a9144b7b335f978f130269fe661423258ae9642df8a188ac72b3d000000000001976a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac000000000100000002060d3cb6dfb7ffe85e2908010fea63190c9707e96fc7448128eb895b5e222771030000006b483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909dfeffffff7b2d8a8263cffbdb722e2a5c74166e6f2258634e277c0b08f51b578b667e2fba000000006a473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eeefeffffff02209a1d00000000001976a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac40420f00000000001976a914d0fce8f064cd1059a6a11501dd66fe42368572b088accb250800'; - var blockIndex = { - 'hash': '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', - 'blockheight': 533974, - 'chainwork': '0000000000000000000000000000000000000000000000054626b1839ade284a', - 'previousblockhash': '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', - 'height': 533974 + var blockOverview = { + hash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + height: 533974, + chainWork: '0000000000000000000000000000000000000000000000054626b1839ade284a', + prevHash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', + txids: [ + '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', + 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1' + ] }; - var block = bitcore.Block.fromBuffer(new Buffer(blockHex, 'hex')); + var transactionDetails = { + '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd': { + hex: '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000', + coinbase: true, + version: 1, + blockTimestamp: 1440987503, + blockHash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + height: 533974, + inputSatoshis: 0, + outputSatoshis: 1250040000, + feeSatoshis: 0, + locktime: 0, + hash: '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', + inputs: [ + { + script: '03d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000', + sequence: 4294967295 + } + ], + outputs: [ + { + address: 'mq4oDPjmNWnBxbzx7qouzhpCSTMePUtYDF', + script: '76a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac', + scriptAsm: 'OP_DUP OP_HASH160 68bedce8982d25c3b6b03f6238cbad00378b8ead OP_EQUALVERIFY OP_CHECKSIG', + satoshis: 1250040000 + } + ] + }, + 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0': { + hex: '0100000002ad5a14ae9d0f3221b790c4fc590fddceea1456e5692d8c4bf1ff7175f2b0c987000000008b4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff9621ac65bc22ea593ca9a61a8d63e461bf3d3f277989df5d3bd33ddfae0aa1d8000000008a4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff02dc374401000000001976a9144b7b335f978f130269fe661423258ae9642df8a188ac72b3d000000000001976a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac00000000', + inputSatoshis: 34955390, + outputSatoshis: 34925390, + feeSatoshis: 30000, + version: 1, + hash: 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0', + blockTimestamp: 1440987503, + height: 533974, + blockHash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + locktime: 0, + inputs: [ + { + satoshis: 18535505, + address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + script: '4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + scriptAsm: '30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + prevTxId: '87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad', + outputIndex: 0, + sequence: 4294967295 + }, + { + address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + script: '4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + scriptAsm: '30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307', + satoshis: 16419885, + sequence: 4294967295, + prevTxId: 'd8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196', + outputIndex: 0 + } + ], + outputs: [ + { + address: 'mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X', + script: '76a9144b7b335f978f130269fe661423258ae9642df8a188ac', + scriptAsm: 'OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG', + satoshis: 21247964 + }, + { + script: '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac', + scriptAsm: 'OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG', + address: 'mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f', + satoshis: 13677426, + spentTxId: '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec', + spentIndex: 1, + spentHeight: 200 + } + ] + }, + '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1': { + hex: '0100000002060d3cb6dfb7ffe85e2908010fea63190c9707e96fc7448128eb895b5e222771030000006b483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909dfeffffff7b2d8a8263cffbdb722e2a5c74166e6f2258634e277c0b08f51b578b667e2fba000000006a473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eeefeffffff02209a1d00000000001976a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac40420f00000000001976a914d0fce8f064cd1059a6a11501dd66fe42368572b088accb250800', + blockHash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', + blockTimestamp: 1440987503, + height: 533974, + locktime: 533963, + inputSatoshis: 2950000, + outputSatoshis: 2940000, + feeSatoshis: 10000, + version: 1, + hash: '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1', + inputs: [ + { + address: 'mgZK8zpudWoAaAwpLQSgc9t9PJJyEBpBdJ', + satoshis: 990000, + script: '483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', + scriptAsm: '3045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901 0346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909d', + sequence: 4294967294, + outputIndex: 3, + prevTxId: '7127225e5b89eb288144c76fe907970c1963ea0f0108295ee8ffb7dfb63c0d06' + }, + { + address: 'n4oM7bPuC4ZPdCEDvtw9xGYQC7jmi5S6F4', + satoshis: 1960000, + script: '473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', + scriptAsm: '3044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c01 03371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eee', + prevTxId: 'ba2f7e668b571bf5080b7c274e6358226f6e16745c2a2e72dbfbcf63828a2d7b', + sequence: 4294967294, + outputIndex : 0 + } + ], + outputs: [ + { + spentTxId: '9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9', + spentIndex: 1, + spentHeight: 200, + satoshis: 1940000, + script: '76a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac', + scriptAsm: 'OP_DUP OP_HASH160 8e451eec7ca0a1764b4ab119274efdd2727b3c85 OP_EQUALVERIFY OP_CHECKSIG', + address: 'mtVD3tdifBNujYzZ5N7PgXfKk4Bc85tDKA' + }, + { + spentTxId: '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc', + spentIndex: 34, + spentHeight: 200, + script: '76a914d0fce8f064cd1059a6a11501dd66fe42368572b088ac', + scriptAsm: 'OP_DUP OP_HASH160 d0fce8f064cd1059a6a11501dd66fe42368572b0 OP_EQUALVERIFY OP_CHECKSIG', + address: 'mzZypShcs1B35udnkqeYeJy8rUdgHDDvKG', + satoshis: 1000000 + } + ] + } + }; var node = { - getBlock: sinon.stub().callsArgWith(1, null, block), + getBlockOverview: sinon.stub().callsArgWith(1, null, blockOverview), + getDetailedTransaction: function(txid, callback) { + callback(null, transactionDetails[txid]); + }, services: { bitcoind: { - getBlockHeader: sinon.stub().callsArgWith(1, null, blockIndex), height: 534209 } }, network: 'testnet' }; - bitcore.Transaction.prototype.populateSpentInfo = _.noop(); - sandbox.stub(bitcore.Transaction.prototype, 'populateSpentInfo', function(db, options, callback) { - if (this.hash === 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0') { - this.outputs[1].__spentTxId = '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec'; - this.outputs[1].__spentIndex = 1; - this.outputs[1].__spentHeight = 200; - } else if (this.hash === '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1') { - this.outputs[0].__spentTxId = '9a213b879da9073a9a30606f9046f35f36f268cbf03f6242993a97c4c07c00b9'; - this.outputs[0].__spentIndex = 1; - this.outputs[0].__spentHeight = 200; - - this.outputs[1].__spentTxId = '418d3eb60275957b3456b96902e908abf962e71be4c4f09486564254664951bc'; - this.outputs[1].__spentIndex = 34; - this.outputs[1].__spentHeight = 200; - } - callback(); - }); - - bitcore.Transaction.prototype.populateInputs = _.noop(); - sandbox.stub(bitcore.Transaction.prototype, 'populateInputs', function(db, pool, callback) { - if(this.hash === 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0') { - this.inputs[0].output = new bitcore.Transaction.Output({ - satoshis: 18535505, - script: '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac' - }); - - this.inputs[1].output = new bitcore.Transaction.Output({ - satoshis: 16419885, - script: '76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac' - }); - } else if(this.hash === '2e01c7a4a0e335112236b711c4aaddd02e8dc59ba2cda416e8f80ff06dddd7e1') { - this.inputs[0].output = new bitcore.Transaction.Output({ - satoshis: 990000, - script: '76a9140b6a5b76fab66d809e0f9e9336c79011880ba96188ac' - }); - this.inputs[1].output = new bitcore.Transaction.Output({ - satoshis: 1960000, - script: '76a914ff6498e8c2498cbad016e1bf3a28cfb178995dbd88ac' - }); - } - - callback(); - }); - var transactions = new TxController(node); var insight = { @@ -550,64 +638,77 @@ describe('Transactions', function() { var txinfos = [ { - tx: bitcore.Transaction().fromObject({ - 'hash': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', - 'version': 1, - 'inputs': [ + tx: { + hex: '010000000125c46caa6d839435b43c20d6d48978e677841244b37a09f6f6cd29bfaf5b5eea010000006b483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6feffffff02a913dda5000000001976a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac809fd500000000001976a9149713201957f42379e574d7c70d506ee49c2c8ad688ac49260800', + hash: 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + version: 1, + inputs: [ { - 'prevTxId': 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', - 'outputIndex': 1, - 'sequenceNumber': 4294967294, - 'script': '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', - 'scriptString': '72 0x3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 33 0x03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', - 'output': { - 'satoshis': 2796764565, - 'script': '76a91488b1fe8aec5ae4358a11447a2f22b2781faedb9b88ac' - } + prevTxId: 'ea5e5bafbf29cdf6f6097ab344128477e67889d4d6203cb43594836daa6cc425', + outputIndex: 1, + sequence: 4294967294, + script: '483045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a6012103acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + scriptAsm: '3045022100f4d169783bef70e3943d2a617cce55d9fe4e33fc6f9880b8277265e2f619a97002201238648abcdf52960500664e969046d41755f7fc371971ebc78002fc418465a601 03acdcd31d51272403ce0829447e59e2ac9e08ed0bf92011cbf7420addf24534e6', + satoshis: 2796764565, + address: 'msyjRQQ88MabQmyafpKCjBHUwuJ49tVjcb' } ], - 'outputs': [ + outputs: [ { - 'satoshis': 2782729129, - 'script': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac' + satoshis: 2782729129, + address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er', + script: '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac', + scriptAsm: 'OP_DUP OP_HASH160 3583efb5e64a4668c6c54bb5fcc30af4417b4f2d OP_EQUALVERIFY OP_CHECKSIG' }, { - 'satoshis': 14000000, - 'script': '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac' + satoshis: 14000000, + address: 'muHmEsjhjmATf9i3T9gHyeQoce9LXe2dWz', + script: '76a9149713201957f42379e574d7c70d506ee49c2c8ad688ac', + scriptAsm: 'OP_DUP OP_HASH160 9713201957f42379e574d7c70d506ee49c2c8ad6 OP_EQUALVERIFY OP_CHECKSIG' } ], - 'nLockTime': 534089 - }) + inputSatoshis: 2796764565, + outputSatoshis: 2796729129, + feeSatoshis: 35436, + locktime: 534089 + } }, { - tx: bitcore.Transaction().fromObject({ - 'hash': '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', - 'version': 1, - 'inputs': [ + tx: { + hex: '0100000001c7f1230d689647ccbff2aae4ddeeccf26aa8836fea709552c9fa0962b9c30ebb000000006a47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24feffffff02bce0c9a4000000001976a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac80a81201000000001976a914011d2963b619186a318f768dddfd98cd553912a088ac53260800', + hash: '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3', + version: 1, + inputs: [ { - 'prevTxId': 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', - 'outputIndex': 0, - 'sequenceNumber': 4294967294, - 'script': '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', - 'scriptString': '71 0x304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 33 0x034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', - 'output': { - 'satoshis': 2782729129, - 'script': '76a9143583efb5e64a4668c6c54bb5fcc30af4417b4f2d88ac' - } + prevTxId: 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + outputIndex: 0, + sequence: 4294967294, + script: '47304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d5640121034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + scriptAsm: '304402201ee69281db6b95bb1aa3074059b67581635b719e8f64e4c2694db6ec56ad9447022011e91528996ea459b1fb2c0b59363fecbefe4bc2ca90f7b2382bdaa358f2d56401 034cc057b12a68ee79df998004b9a1341bbb18b17ea4939bebaa3bac001e940f24', + satoshis: 2782729129, + address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er' } ], - 'outputs': [ + outputs: [ { - 'satoshis': 2764693692, - 'script': '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac' + satoshis: 2764693692, + address: 'moSPsU4p2C2gssiniJ1JNH4fB9xs633tLv', + script: '76a91456e446bc3489543d8324c6d0271524c0bd0506dd88ac', + scriptAsm: 'OP_DUP OP_HASH160 56e446bc3489543d8324c6d0271524c0bd0506dd OP_EQUALVERIFY OP_CHECKSIG' }, { - 'satoshis': 18000000, - 'script': '76a914011d2963b619186a318f768dddfd98cd553912a088ac' + satoshis: 18000000, + scriptAsm: 'OP_DUP OP_HASH160 011d2963b619186a318f768dddfd98cd553912a0 OP_EQUALVERIFY OP_CHECKSIG', + script: '76a914011d2963b619186a318f768dddfd98cd553912a088ac', + address: 'mfcquSAitCkUKXaYRZTRZQDfUegnL3kDew', + spentTxId: '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed' } ], - 'nLockTime': 534099 - }) + inputSatoshis: 2782729129, + outputSatoshis: 2782693692, + feeSatoshis: 35437, + locktime: 534099 + } } ]; @@ -616,25 +717,25 @@ describe('Transactions', function() { items: txinfos }; - txinfos[0].tx.__blockHash = '00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520'; - txinfos[0].tx.__timestamp = 1441068774; - txinfos[0].tx.__height = 534105; + txinfos[0].tx.blockHash = '00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520'; + txinfos[0].tx.blockTimestamp = 1441068774; + txinfos[0].tx.height = 534105; - txinfos[1].tx.__blockHash = '0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0'; - txinfos[1].tx.__timestamp = 1441072817; - txinfos[1].tx.__height = 534110; + txinfos[1].tx.blockHash = '0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0'; + txinfos[1].tx.blockTimestamp = 1441072817; + txinfos[1].tx.height = 534110; - txinfos[0].tx.outputs[0].__spentTxId = '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3'; - txinfos[0].tx.outputs[0].__spentIndex = 0; - txinfos[0].tx.outputs[0].__spentHeight = 199; + txinfos[0].tx.outputs[0].spentTxId = '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3'; + txinfos[0].tx.outputs[0].spentIndex = 0; + txinfos[0].tx.outputs[0].spentHeight = 199; - txinfos[1].tx.outputs[0].__spentTxId = '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2'; - txinfos[1].tx.outputs[0].__spentIndex = 0; - txinfos[1].tx.outputs[0].__spentHeight = 134; + txinfos[1].tx.outputs[0].spentTxId = '661194e5533a395ce9076f292b7e0fb28fe94cd8832a81b4aa0517ff58c1ddd2'; + txinfos[1].tx.outputs[0].spentIndex = 0; + txinfos[1].tx.outputs[0].spentHeight = 134; - txinfos[1].tx.outputs[1].__spentTxId = '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed'; - txinfos[1].tx.outputs[1].__spentIndex = 0; - txinfos[1].tx.outputs[1].__spentHeight = 112; + txinfos[1].tx.outputs[1].spentTxId = '71a9e60c0341c9c258367f1a6d4253276f16e207bf84f41ff7412d8958a81bed'; + txinfos[1].tx.outputs[1].spentIndex = 0; + txinfos[1].tx.outputs[1].spentHeight = 112; var node = { getAddressHistory: sinon.stub().callsArgWith(2, null, historyResult), From 11874a195701fb087878d3b08e52e1b744123a5a Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 16 May 2016 18:27:27 -0400 Subject: [PATCH 52/57] blocks: handle out of range height as 404 not found --- lib/blocks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index f7f97ae..b05c467 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -47,7 +47,7 @@ BlockController.prototype.block = function(req, res, next) { next(); } else { self.node.getBlock(hash, function(err, block) { - if(err && err.code === -5) { + if(err && err.code === -5 || err.code === -8) { return self.common.handleErrors(null, res); } else if(err) { return self.common.handleErrors(err, res); @@ -75,7 +75,7 @@ BlockController.prototype.rawBlock = function(req, res, next) { var blockArg = req.params.blockArg; self.node.getRawBlock(blockArg, function(err, blockBuffer) { - if(err && err.code === -5) { + if(err && err.code === -5 || err.code === -8) { return self.common.handleErrors(null, res); } else if(err) { return self.common.handleErrors(err, res); From 61f0c3063a0d101cdbd7776a39a0429ab0abc8dd Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 16 May 2016 18:32:08 -0400 Subject: [PATCH 53/57] bitcoind: fix error handling bug --- lib/blocks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index b05c467..174faf7 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -47,7 +47,7 @@ BlockController.prototype.block = function(req, res, next) { next(); } else { self.node.getBlock(hash, function(err, block) { - if(err && err.code === -5 || err.code === -8) { + if((err && err.code === -5) || (err && err.code === -8)) { return self.common.handleErrors(null, res); } else if(err) { return self.common.handleErrors(err, res); @@ -75,7 +75,7 @@ BlockController.prototype.rawBlock = function(req, res, next) { var blockArg = req.params.blockArg; self.node.getRawBlock(blockArg, function(err, blockBuffer) { - if(err && err.code === -5 || err.code === -8) { + if((err && err.code === -5) || (err && err.code === -8)) { return self.common.handleErrors(null, res); } else if(err) { return self.common.handleErrors(err, res); From 72fe25aff9d9cd79c8a9a788b77a7d92ab2cc988 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 25 May 2016 16:03:36 -0400 Subject: [PATCH 54/57] Fix bug with var self = this; --- lib/addresses.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/addresses.js b/lib/addresses.js index beae11f..c4838bc 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -12,7 +12,7 @@ function AddressController(node) { } AddressController.prototype.show = function(req, res) { - var self; + var self = this; var options = { noTxList: parseInt(req.query.noTxList) }; From 2448ad1779da7ae8d4cf78a86260446f40d3f21c Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 25 May 2016 17:16:11 -0400 Subject: [PATCH 55/57] index: log remote connecting ip address --- lib/index.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index ede8025..c8f825a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -109,14 +109,26 @@ InsightAPI.prototype.createLogInfoStream = function() { return stream; }; +InsightAPI.prototype.getRemoteAddress = function(req) { + if (req.headers['cf-connecting-ip']) { + return req.headers['cf-connecting-ip']; + } + return req.socket.remoteAddress; +}; + InsightAPI.prototype.setupRoutes = function(app) { + var self = this; + //Enable rate limiter var limiter = new RateLimiter({node: this.node}); app.use(limiter.middleware()); //Setup logging - var logFormat = ':remote-addr ":method :url" :status :res[content-length] :response-time ":user-agent" '; + morgan.token('remote-forward-addr', function(req){ + return self.getRemoteAddress(req); + }); + var logFormat = ':remote-forward-addr ":method :url" :status :res[content-length] :response-time ":user-agent" '; var logStream = this.createLogInfoStream(); app.use(morgan(logFormat, {stream: logStream})); From 4317f67a2bf8fed7da4565f7610b38170a83a17c Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 26 May 2016 09:17:01 -0400 Subject: [PATCH 56/57] addresses: add coverage to address controller show covers bug fixed in commit 72fe25aff9d9cd79c8a9a788b77a7d92ab2cc988 --- test/addresses.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/addresses.js b/test/addresses.js index b8e5b23..81bd581 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -225,6 +225,30 @@ describe('Addresses', function() { addresses.show(req, res); }); + it('handle error', function() { + var testnode = {}; + testnode.log = {}; + testnode.log.error = sinon.stub(); + var controller = new AddressController(testnode); + controller.getAddressSummary = sinon.stub().callsArgWith(2, new Error('test')); + var req = { + query: { + noTxList: 1 + }, + addr: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er' + }; + var send = sinon.stub(); + var status = sinon.stub().returns({send: send}); + var res = { + status: status + }; + controller.show(req, res); + send.callCount.should.equal(1); + status.callCount.should.equal(1); + status.args[0][0].should.equal(503); + send.args[0][0].should.equal('test'); + }); + it('/balance', function(done) { var insight = 0; From 667a38053b63694b76a85570241310590e8c074f Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 26 May 2016 11:21:36 -0400 Subject: [PATCH 57/57] block: check block argument and fix caching Checks that the argument sent to the endpoint for /block/ and /rawblock/ is a 64 character hexadecimal string (blockHash), otherwise will return 404. Uses a long cache header for for the /rawblock/ endpoint since the result will not change, and a short cache header for the /block/ endpoint since this data references other blocks in the chain that can change. --- README.md | 2 +- lib/blocks.js | 21 +++++++++++++++++++-- lib/index.js | 11 +++++------ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a5cdfaf..8c88edb 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ The unspent outputs format now has `satoshis` and `height`: ``` The `timestamp` property will only be set for unconfirmed transactions and `height` can be used for determining block order. The `confirmationsFromCache` is nolonger set or necessary, confirmation count is only cached for the time between blocks. -There is a new `GET` endpoint or raw blocks at `/rawblock/`, where `blockArg` can be hash or height: +There is a new `GET` endpoint or raw blocks at `/rawblock/`: Response format: ``` diff --git a/lib/blocks.js b/lib/blocks.js index 174faf7..4d286a5 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -2,6 +2,7 @@ var async = require('async'); var bitcore = require('bitcore-lib'); +var _ = bitcore.deps._; var pools = require('../pools.json'); var BN = bitcore.crypto.BN; var LRU = require('lru-cache'); @@ -33,6 +34,22 @@ var BLOCK_LIMIT = 200; BlockController.DEFAULT_BLOCKSUMMARY_CACHE_SIZE = 1000000; BlockController.DEFAULT_BLOCK_CACHE_SIZE = 1000; +function isHexadecimal(hash) { + if (!_.isString(hash)) { + return false; + } + return /^[0-9a-fA-F]+$/.test(hash); +} + +BlockController.prototype.checkBlockHash = function(req, res, next) { + var self = this; + var hash = req.params.blockHash; + if (hash.length < 64 || !isHexadecimal(hash)) { + return self.common.handleErrors(null, res); + } + next(); +}; + /** * Find block by hash ... */ @@ -72,9 +89,9 @@ BlockController.prototype.block = function(req, res, next) { */ BlockController.prototype.rawBlock = function(req, res, next) { var self = this; - var blockArg = req.params.blockArg; + var blockHash = req.params.blockHash; - self.node.getRawBlock(blockArg, function(err, blockBuffer) { + self.node.getRawBlock(blockHash, function(err, blockBuffer) { if((err && err.code === -5) || (err && err.code === -8)) { return self.common.handleErrors(null, res); } else if(err) { diff --git a/lib/index.js b/lib/index.js index c8f825a..08e0843 100644 --- a/lib/index.js +++ b/lib/index.js @@ -154,19 +154,18 @@ InsightAPI.prototype.setupRoutes = function(app) { var blocks = new BlockController(blockOptions); app.get('/blocks', this.cacheShort(), blocks.list.bind(blocks)); - - app.get('/block/:blockHash', this.cacheLong(), blocks.show.bind(blocks)); + app.get('/block/:blockHash', this.cacheShort(), blocks.checkBlockHash.bind(blocks), blocks.show.bind(blocks)); app.param('blockHash', blocks.block.bind(blocks)); - app.get('/rawblock/:blockArg', this.cacheLong(), blocks.showRaw.bind(blocks)); - app.param('blockArg', blocks.rawBlock.bind(blocks)); + app.get('/rawblock/:blockHash', this.cacheLong(), blocks.checkBlockHash.bind(blocks), blocks.showRaw.bind(blocks)); + app.param('blockHash', blocks.rawBlock.bind(blocks)); - app.get('/block-index/:height', this.cacheLong(), blocks.blockIndex.bind(blocks)); + app.get('/block-index/:height', this.cacheShort(), blocks.blockIndex.bind(blocks)); app.param('height', blocks.blockIndex.bind(blocks)); // Transaction routes var transactions = new TxController(this.node); - app.get('/tx/:txid', this.cacheLong(), transactions.show.bind(transactions)); + app.get('/tx/:txid', this.cacheShort(), transactions.show.bind(transactions)); app.param('txid', transactions.transaction.bind(transactions)); app.get('/txs', this.cacheShort(), transactions.list.bind(transactions)); app.post('/tx/send', transactions.send.bind(transactions));