Merge branch 'master' of github.com:kleetus/insight-api

This commit is contained in:
Chris Kleeschulte 2017-11-13 14:14:24 -05:00
commit 1b86e3636f
10 changed files with 564 additions and 40 deletions

View File

@ -7,18 +7,18 @@ This is a backend-only service. If you're looking for the web frontend applicati
## Getting Started ## Getting Started
```bashl ```bashl
npm install -g bitcore-node@latest npm install -g bitcore@latest
bitcore-node create mynode bitcore create mynode
cd mynode cd mynode
bitcore-node install insight-api bitcore install insight-api
bitcore-node start bitcore start
``` ```
The API endpoints will be available by default at: `http://localhost:3001/insight-api/` The API endpoints will be available by default at: `http://localhost:3001/insight-api/`
## Prerequisites ## Prerequisites
- [Bitcore Node 3.x](https://github.com/bitpay/bitcore-node) - [Bitcore 5.x](https://github.com/bitpay/bitcore)
**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. **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.

View File

@ -7,12 +7,12 @@ var TxController = require('./transactions');
var Common = require('./common'); var Common = require('./common');
var _ = require('lodash'); var _ = require('lodash');
function AddressController(node) { function AddressController(node, translateAddresses) {
this.node = node; this.node = node;
this._address = this.node.services.address; this._address = this.node.services.address;
this._block = this.node.services.block; this._block = this.node.services.block;
this.txController = new TxController(node); this.txController = new TxController(node, translateAddresses);
this.common = new Common({log: this.node.log}); this.common = new Common({log: this.node.log, translateAddresses: translateAddresses});
this._block = this.node.services.block; this._block = this.node.services.block;
} }
@ -28,10 +28,14 @@ AddressController.prototype.show = function(req, res) {
} }
this._address.getAddressSummary(req.addr, options, function(err, data) { this._address.getAddressSummary(req.addr, options, function(err, data) {
if(err) { if(err) {
return self.common.handleErrors(err, res); return self.common.handleErrors(err, res);
} }
if (data && data.addrStr)
data.addrStr = self.common.translateOutputAddress(data.addrStr);
res.jsonp(data); res.jsonp(data);
}); });
}; };
@ -64,6 +68,7 @@ AddressController.prototype.addressSummarySubQuery = function(req, res, param) {
}; };
AddressController.prototype.getAddressSummary = function(address, options, callback) { AddressController.prototype.getAddressSummary = function(address, options, callback) {
var self = this;
this._address.getAddressSummary(address, options, function(err, summary) { this._address.getAddressSummary(address, options, function(err, summary) {
if(err) { if(err) {
@ -71,7 +76,7 @@ AddressController.prototype.getAddressSummary = function(address, options, callb
} }
var transformed = { var transformed = {
addrStr: address, address: self.common.translateOutputAddress(address),
balance: Unit.fromSatoshis(summary.balance).toBTC(), balance: Unit.fromSatoshis(summary.balance).toBTC(),
balanceSat: summary.balance, balanceSat: summary.balance,
totalReceived: Unit.fromSatoshis(summary.totalReceived).toBTC(), totalReceived: Unit.fromSatoshis(summary.totalReceived).toBTC(),
@ -90,6 +95,7 @@ AddressController.prototype.getAddressSummary = function(address, options, callb
}; };
AddressController.prototype.checkAddrs = function(req, res, next) { AddressController.prototype.checkAddrs = function(req, res, next) {
var self = this;
function makeArray(addrs) { function makeArray(addrs) {
if (_.isString(addrs)) { if (_.isString(addrs)) {
@ -114,29 +120,18 @@ AddressController.prototype.checkAddrs = function(req, res, next) {
}, res); }, res);
} }
var inValid = this.check(req.addrs); try {
req.addrs = self.common.translateInputAddresses(req.addrs);
if (inValid) { req.addr = req.addrs[0];
} catch(e) {
console.log('[addresses.js.130]', e); //TODO
return this.common.handleErrors({ return this.common.handleErrors({
message: 'Invalid address: ' + inValid.message, message: 'Invalid address: ' + e,
code: 1 code: 1
}, res); }, res);
} };
next(); next();
};
AddressController.prototype.check = function(addresses) {
for(var i = 0; i < addresses.length; i++) {
try {
new bitcore.Address(addresses[i]);
} catch(e) {
return addresses[i];
}
}
}; };
AddressController.prototype.utxo = function(req, res) { AddressController.prototype.utxo = function(req, res) {
@ -154,9 +149,11 @@ AddressController.prototype.utxo = function(req, res) {
}); });
}; };
AddressController.prototype.transformUtxo = function(utxoArg) { AddressController.prototype.transformUtxo = function(utxoArg) {
var utxo = { var utxo = {
address: utxoArg.address, address: this.common.translateOutputAddress(utxoArg.address),
txid: utxoArg.txid, txid: utxoArg.txid,
vout: utxoArg.vout, vout: utxoArg.vout,
scriptPubKey: utxoArg.scriptPubKey, scriptPubKey: utxoArg.scriptPubKey,
@ -223,8 +220,9 @@ AddressController.prototype.multiutxo = function(req, res) {
if (utxos.length - 1 === i) { if (utxos.length - 1 === i) {
sep = ''; sep = '';
} }
utxos[i] = self.transformUtxo(utxos[i]);
cache.push(utxos[i]); cache.push(utxos[i]);
res.write(JSON.stringify(self.transformUtxo(utxos[i])) + sep); res.write(JSON.stringify(utxos[i]) + sep);
} }
sep = ','; sep = ',';

56
lib/addresstranslator.js Normal file
View File

@ -0,0 +1,56 @@
var Bitcore_ = {
btc: require('bitcore-lib'),
bch: require('bitcore-lib-cash')
};
var _ = require('lodash');
function AddressTranslator() {
};
AddressTranslator.getAddressCoin = function(address) {
try {
new Bitcore_['btc'].Address(address);
return 'btc';
} catch (e) {
try {
new Bitcore_['bch'].Address(address);
return 'bch';
} catch (e) {
return;
}
}
};
AddressTranslator.translate = function(addresses, coin, origCoin) {
var wasArray = true;
if (!_.isArray(addresses)) {
wasArray = false;
addresses = [addresses];
}
origCoin = origCoin || AddressTranslator.getAddressCoin(addresses[0]);
var ret = _.map(addresses, function(x) {
var orig = new Bitcore_[origCoin].Address(x).toObject();
return Bitcore_[coin].Address.fromObject(orig).toString();
});
if (wasArray)
return ret;
else
return ret[0];
};
AddressTranslator.translateInput = function(addresses) {
return this.translate(addresses, 'btc', 'bch');
}
AddressTranslator.translateOutput = function(addresses) {
return this.translate(addresses, 'bch', 'btc');
}
module.exports = AddressTranslator;

View File

@ -1,7 +1,12 @@
'use strict'; 'use strict';
var _ = require('lodash');
var AddressTranslator = require('./addresstranslator');
var bitcore = require('bitcore-lib');
function Common(options) { function Common(options) {
this.log = options.log; this.log = options.log;
this.translateAddresses = options.translateAddresses;
} }
Common.prototype.notReady = function (err, res, p) { Common.prototype.notReady = function (err, res, p) {
@ -21,4 +26,43 @@ Common.prototype.handleErrors = function (err, res) {
} }
}; };
Common.prototype.translateInputAddresses= function(addresses) {
var self = this;
if (!addresses) return;
if (!_.isArray(addresses))
addresses = [ addresses ];
function check(addresses) {
if (!addresses) return;
for(var i = 0; i < addresses.length; i++) {
try {
new bitcore.Address(addresses[i]);
} catch(e) {
throw addresses[i];
}
}
}
if (this.translateAddresses) {
addresses = AddressTranslator.translateInput(addresses);
} else
check(addresses);
return addresses;
};
Common.prototype.translateOutputAddress= function(address) {
if (!this.translateAddresses) return address;
return AddressTranslator.translateOutput(address);
};
module.exports = Common; module.exports = Common;

View File

@ -27,6 +27,7 @@ var EventEmitter = require('events').EventEmitter;
* @param {Number} options.cacheShortSeconds - The time to cache short lived cache responses. * @param {Number} options.cacheShortSeconds - The time to cache short lived cache responses.
* @param {Number} options.cacheLongSeconds - The time to cache long lived cache responses. * @param {Number} options.cacheLongSeconds - The time to cache long lived cache responses.
* @param {String} options.routePrefix - The URL route prefix * @param {String} options.routePrefix - The URL route prefix
* @param {String} options.translateAddresses - Translate request and output address to Copay's BCH address version (see https://support.bitpay.com/hc/en-us/articles/115004671663-BitPay-s-Adopted-Conventions-for-Bitcoin-Cash-Addresses-URIs-and-Payment-Requests)
*/ */
var InsightAPI = function(options) { var InsightAPI = function(options) {
BaseService.call(this, options); BaseService.call(this, options);
@ -47,6 +48,7 @@ var InsightAPI = function(options) {
this.rateLimiterOptions = options.rateLimiterOptions; this.rateLimiterOptions = options.rateLimiterOptions;
this.disableRateLimiter = options.disableRateLimiter; this.disableRateLimiter = options.disableRateLimiter;
this.translateAddresses = options.translateAddresses;
this.blockSummaryCacheSize = options.blockSummaryCacheSize || BlockController.DEFAULT_BLOCKSUMMARY_CACHE_SIZE; this.blockSummaryCacheSize = options.blockSummaryCacheSize || BlockController.DEFAULT_BLOCKSUMMARY_CACHE_SIZE;
this.blockCacheSize = options.blockCacheSize || BlockController.DEFAULT_BLOCK_CACHE_SIZE; this.blockCacheSize = options.blockCacheSize || BlockController.DEFAULT_BLOCK_CACHE_SIZE;
@ -201,7 +203,7 @@ InsightAPI.prototype.setupRoutes = function(app) {
app.param('height', blocks.blockIndex.bind(blocks)); app.param('height', blocks.blockIndex.bind(blocks));
// Transaction routes // Transaction routes
var transactions = new TxController(this.node); var transactions = new TxController(this.node, this.translateAddresses);
app.get('/tx/:txid', this.cacheShort(), transactions.show.bind(transactions)); app.get('/tx/:txid', this.cacheShort(), transactions.show.bind(transactions));
app.param('txid', transactions.transaction.bind(transactions)); app.param('txid', transactions.transaction.bind(transactions));
app.get('/txs', this.cacheShort(), transactions.list.bind(transactions)); app.get('/txs', this.cacheShort(), transactions.list.bind(transactions));
@ -212,7 +214,7 @@ InsightAPI.prototype.setupRoutes = function(app) {
app.param('txid', transactions.rawTransaction.bind(transactions)); app.param('txid', transactions.rawTransaction.bind(transactions));
// Address routes // Address routes
var addresses = new AddressController(this.node); var addresses = new AddressController(this.node, this.translateAddresses);
app.get('/addr/:addr', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.show.bind(addresses)); app.get('/addr/:addr', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.show.bind(addresses));
app.get('/addr/:addr/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.utxo.bind(addresses)); app.get('/addr/:addr/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.utxo.bind(addresses));
app.get('/addrs/:addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses)); app.get('/addrs/:addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));

View File

@ -8,9 +8,9 @@ var async = require('async');
var MAXINT = 0xffffffff; // Math.pow(2, 32) - 1; var MAXINT = 0xffffffff; // Math.pow(2, 32) - 1;
function TxController(node) { function TxController(node, translateAddresses) {
this.node = node; this.node = node;
this.common = new Common({log: this.node.log}); this.common = new Common({log: this.node.log, translateAddresses: translateAddresses});
this._block = this.node.services.block; this._block = this.node.services.block;
this._transaction = this.node.services.transaction; this._transaction = this.node.services.transaction;
this._address = this.node.services.address; this._address = this.node.services.address;
@ -134,7 +134,8 @@ TxController.prototype.transformInput = function(options, input, index) {
var address = input.getAddress(); var address = input.getAddress();
if (address) { if (address) {
address.network = this._network; address.network = this._network;
transformed.addr = address.toString(); transformed.addr = this.common.translateOutputAddress(address.toString());
} else { } else {
transformed.addr = null; transformed.addr = null;
} }
@ -170,13 +171,16 @@ TxController.prototype.transformOutput = function(options, output, index) {
var address = output.getAddress(); var address = output.getAddress();
if (address) { if (address) {
address.network = this._network; address.network = this._network;
transformed.scriptPubKey.addresses = [address.toString()]; transformed.scriptPubKey.addresses = [this.common.translateOutputAddress(address.toString())];
transformed.scriptPubKey.type = address.getType(); transformed.scriptPubKey.type = address.getType();
} }
return transformed; return transformed;
}; };
TxController.prototype.transformInvTransaction = function(transaction) { TxController.prototype.transformInvTransaction = function(transaction) {
var self = this;
var valueOut = 0; var valueOut = 0;
var vout = []; var vout = [];
for (var i = 0; i < transaction.outputs.length; i++) { for (var i = 0; i < transaction.outputs.length; i++) {
@ -190,7 +194,7 @@ TxController.prototype.transformInvTransaction = function(transaction) {
} }
address.network = this._network; address.network = this._network;
address = address.toString(); address = self.common.translateOutputAddress(address.toString());
var obj = {}; var obj = {};
obj[address] = output.value; obj[address] = output.value;
@ -244,7 +248,7 @@ TxController.prototype.list = function(req, res) {
var self = this; var self = this;
var blockHash = req.query.block; var blockHash = req.query.block;
var address = req.query.address; var address = this.common.translateInputAddresses(req.query.address);
var page = parseInt(req.query.pageNum) || 0; var page = parseInt(req.query.pageNum) || 0;
var pageLength = 10; var pageLength = 10;
var pagesTotal = 1; var pagesTotal = 1;

62
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "insight-api", "name": "insight-api",
"version": "5.0.0-beta.41", "version": "5.0.0-beta.42",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -80,6 +80,14 @@
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true "dev": true
}, },
"base-x": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.2.tgz",
"integrity": "sha1-v4c4YbdRQnm3lp80CSnquHwR0TA=",
"requires": {
"safe-buffer": "5.1.1"
}
},
"base64-arraybuffer": { "base64-arraybuffer": {
"version": "0.1.5", "version": "0.1.5",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
@ -184,6 +192,58 @@
} }
} }
}, },
"bitcore-lib-cash": {
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/bitcore-lib-cash/-/bitcore-lib-cash-0.15.1.tgz",
"integrity": "sha512-2fftReEqbkohCwiblBGteEX5S7lc6oTGM1QyDr6rz88QA7xLqhtVkT9hWrwirZfw6H4IfApS2gAAtHGExCqMsw==",
"requires": {
"bn.js": "4.11.8",
"bs58": "4.0.1",
"buffer-compare": "1.1.1",
"elliptic": "6.4.0",
"inherits": "2.0.1",
"lodash": "4.17.4"
},
"dependencies": {
"bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
},
"bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"requires": {
"base-x": "3.0.2"
}
},
"buffer-compare": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz",
"integrity": "sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY="
},
"elliptic": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
"integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
"requires": {
"bn.js": "4.11.8",
"brorand": "1.1.0",
"hash.js": "1.1.3",
"hmac-drbg": "1.0.1",
"inherits": "2.0.1",
"minimalistic-assert": "1.0.0",
"minimalistic-crypto-utils": "1.0.1"
}
},
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
}
}
},
"bitcore-message": { "bitcore-message": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/bitcore-message/-/bitcore-message-1.0.2.tgz", "resolved": "https://registry.npmjs.org/bitcore-message/-/bitcore-message-1.0.2.tgz",

View File

@ -1,7 +1,7 @@
{ {
"name": "insight-api", "name": "insight-api",
"description": "A Bitcoin blockchain REST and web socket API service for Bitcore Node.", "description": "A Bitcoin blockchain REST and web socket API service for Bitcore Node.",
"version": "5.0.0-beta.41", "version": "5.0.0-beta.42",
"repository": "git://github.com/bitpay/insight-api.git", "repository": "git://github.com/bitpay/insight-api.git",
"bugs": { "bugs": {
"url": "https://github.com/bitpay/insight-api/issues" "url": "https://github.com/bitpay/insight-api/issues"
@ -32,6 +32,7 @@
"async": "*", "async": "*",
"bcoin": "bcoin-org/bcoin#886008a1822ce1da7fa8395ee7db4bcc1750a28a", "bcoin": "bcoin-org/bcoin#886008a1822ce1da7fa8395ee7db4bcc1750a28a",
"bitcore-lib": "5.0.0-beta.1", "bitcore-lib": "5.0.0-beta.1",
"bitcore-lib-cash": "0.15.1",
"bitcore-message": "^1.0.1", "bitcore-message": "^1.0.1",
"body-parser": "^1.13.3", "body-parser": "^1.13.3",
"compression": "^1.6.1", "compression": "^1.6.1",

306
test/addressesCash.js Normal file
View File

@ -0,0 +1,306 @@
'use strict';
var should = require('should');
var sinon = require('sinon');
var AddressController = require('../lib/addresses');
var _ = require('lodash');
var bitcore = require('bitcore-lib');
var bcoin = require('bcoin');
var rawHex = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d010bffffffff0100f2052a010000004341047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77ac00000000";
var bcoinTx = bcoin.tx.fromRaw(rawHex, 'hex');
bcoinTx.__blockhash = '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013';
bcoinTx.blockhash = '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013';
bcoinTx.__height = 534181;
bcoinTx.__timestamp = 1441116143;
bcoinTx.outputSatoshis = 53829829;
var txinfos2 = {
totalCount: 1,
items: [ bcoinTx ]
};
var utxos = [
{
'address': '1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA',
'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73',
'vout': 1,
'timestamp': 1441116143,
'satoshis': 53320000,
'scriptPubKey': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac',
'height': 534181,
'confirmations': 50
},
{
'address': '3EDL9HSincwLGfYbWPQ7LXtc4VqdwGoraS',
'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73',
'vout': 2,
'timestamp': 1441116143,
'satoshis': 289829,
'scriptPubKey': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac',
'height': 534181,
'confirmations': 50
}
];
describe('Addresses / Bitcoin Cash', function() {
var summary = {
addrStr: 'CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz',
balance: 0,
totalReceivedSat: 2782729129,
totalSentSat: 2782729129,
unconfirmedBalance: 0,
appearances: 2,
unconfirmedAppearances: 0,
txids: [
'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7',
'01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3'
]
};
describe('/addr/:addr', function() {
var node = {
services: {
address: {
getAddressSummary: sinon.stub().callsArgWith(2, null, summary)
}
}
};
var addresses = new AddressController(node, true);
var req = {
addr: '',
query: {}
};
it('checkAddrs', function(done) {
var insight = 0;
var req = {
query: {
noTxList: 1
},
params: {
addr: 'CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz'
},
};
var send = sinon.stub();
var status = sinon.stub().returns({send: send});
var res = {
status: status
};
addresses.checkAddrs(req, res, function(req2) {
req.addr.should.equal('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA');
req.addrs[0].should.equal('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA');
done();
});
});
});
describe('/addr/:addr/utxo', function() {
it('should have correct data', function(done) {
var insight = [
{
'address': 'CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz',
'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73',
'vout': 1,
'ts': 1441116143,
'scriptPubKey': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac',
'amount': 0.5332,
'confirmations': 50,
'height': 534181,
'satoshis': 53320000,
'confirmationsFromCache': true
}
];
var todos = [
{
confirmationsFromCache: true
}
];
var node = {
services: {
block: {
getTip: sinon.stub().returns({ height: 534230 })
},
address: {
getAddressUnspentOutputs: sinon.stub().callsArgWith(2, null, utxos.slice(0, 1))
}
},
};
var addresses = new AddressController(node, true);
var req = {
addr: 'CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz'
};
var res = {
jsonp: function(data) {
var merged = _.merge(data, todos);
should(merged).eql(insight);
done();
}
};
addresses.utxo(req, res);
});
});
describe('/addrs/:addrs/utxo', function() {
it('should have the correct data', function(done) {
var insight = [
{
'address': 'CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz',
'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73',
'vout': 1,
'ts': 1441116143,
'scriptPubKey': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac',
'amount': 0.5332,
'height': 534181,
'satoshis': 53320000,
'confirmations': 50
},
{
'address': 'HK3Sc5sodw9ztqRdN54GJvR969rejftcS9',
'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73',
'vout': 2,
'ts': 1441116143,
'scriptPubKey': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac',
'amount': 0.00289829,
'height': 534181,
'satoshis': 289829,
'confirmations': 50
}
];
var utxoStub = sinon.stub();
utxoStub.onCall(0).callsArgWith(2, null, [utxos[0]]);
utxoStub.onCall(1).callsArgWith(2, null, [utxos[1]]);
var node = {
services: {
address: {
getAddressUnspentOutputs: utxoStub
},
block: {
getTip: sinon.stub().returns({ height: 534230 })
}
},
};
var addresses = new AddressController(node, true);
var req = {
addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD'
};
var finalData = '';
var res = {
write: function(data) {
finalData += data;
},
end: function() {
var finalObject = JSON.parse(finalData);
finalObject.should.eql(insight);
done();
}
};
addresses.multiutxo(req, res);
});
});
describe('/addrs/:addrs/txs', function() {
it('should have correct data', function(done) {
var insight = {
'totalItems': 1,
'from': 0,
'to': 1,
'items': [
{
'txid': '9b0fc92260312ce44e74ef369f5c66bbb85848f2eddd5a7a1cde251e54ccfdd5',
'version': 1,
'isCoinBase': true,
'locktime': 0,
'vin': [
{
'coinbase': '04ffff001d010b',
'sequence': 4294967295,
'n': 0
}
],
'vout': [
{
'value': '50.00000000',
'n': 0,
'scriptPubKey': {
'asm': '047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77 OP_CHECKSIG',
'hex': '41047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77ac',
'type': 'pubkeyhash',
'addresses': [
'CYognBa8KGDnHMcyM7siKgxRkCkUqLb4YM'
]
},
spentHeight: null,
spentIndex: null,
spentTxId: null
}
],
'blockhash': '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013',
'blockheight': 534181,
'confirmations': 52,
'time': 1441116143,
'blocktime': 1441116143,
'valueOut': 0.53829829,
'size': 134
}
]
};
var node = {
services: {
address: {
getAddressHistory: sinon.stub().callsArgWith(2, null, txinfos2),
},
block: {
getTip: sinon.stub().returns({ height: 534232 })
}
}
};
var addresses = new AddressController(node, true);
var req = {
addrs: 'CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz,HK3Sc5sodw9ztqRdN54GJvR969rejftcS9',
query: {},
body: {}
};
var res = {
jsonp: function(data) {
should(data).eql(insight);
done();
}
};
addresses.multitxs(req, res);
});
});
});

View File

@ -0,0 +1,53 @@
var _ = require('lodash');
var chai = require('chai');
var sinon = require('sinon');
var assert = require('assert');
var should = chai.should;
var AddressTranslator = require('../lib/addresstranslator');
describe('#AddressTranslator', function() {
it('should translate address from btc to bch', function() {
var res = AddressTranslator.translate('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', 'bch');
assert( res == 'CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz');
});
it('should translate address from bch to btc', function() {
var res = AddressTranslator.translateInput('HBf8isgS8EXG1r3X6GP89FmooUmiJ42wHS');
assert(res=='36q2G5FMGvJbPgAVEaiyAsFGmpkhPKwk2r');
});
it('should keep the address if there is nothing to do (bch)', function() {
var res = AddressTranslator.translate('CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz', 'bch');
assert(res=='CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz');
});
it('should keep the address if there is nothing to do (btc)', function() {
var res = AddressTranslator.translate('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', 'btc');
assert(res=='1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA');
});
it('should support 3 params NOK', function() {
var a;
try {
var res = AddressTranslator.translate('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', 'btc', 'bch');
} catch (e) {
a=e.toString();
assert(a.match(/Address has mismatched network type/));
};
});
it('should support 3 params OK', function() {
var res = AddressTranslator.translate('HBf8isgS8EXG1r3X6GP89FmooUmiJ42wHS', 'btc', 'bch');
assert(res=='36q2G5FMGvJbPgAVEaiyAsFGmpkhPKwk2r');
});
it('should work with arrays also', function() {
var res = AddressTranslator.translateOutput(['1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', '37YHiaQnMjy73GS1UpiE8p2Ju6MyrrDw3J', '1DuPdCpGzVX73kBYaAbu5XDNDgE2Lza5Ed']);
assert(res[0] == 'CcJ4qUfyQ8x5NwhAeCQkrBSWVeXxXghcNz');
assert(res[1] == 'HCNQBNqsD4BmfSK3LWNP7CYqvkNznSrXS3');
assert(res[2] == 'CVNHCFALsYVdwt5yFuvpf2qPqoSSGtvY7t');
});
});