Merge remote-tracking branch 'upstream/feat/addr-translator'
This commit is contained in:
commit
3c1f4d7ef9
10
README.md
10
README.md
@ -7,18 +7,18 @@ This is a backend-only service. If you're looking for the web frontend applicati
|
||||
## Getting Started
|
||||
|
||||
```bashl
|
||||
npm install -g bitcore-node@latest
|
||||
bitcore-node create mynode
|
||||
npm install -g bitcore@latest
|
||||
bitcore create mynode
|
||||
cd mynode
|
||||
bitcore-node install insight-api
|
||||
bitcore-node start
|
||||
bitcore install insight-api
|
||||
bitcore start
|
||||
```
|
||||
|
||||
The API endpoints will be available by default at: `http://localhost:3001/insight-api/`
|
||||
|
||||
## 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.
|
||||
|
||||
|
||||
@ -8,12 +8,12 @@ var Common = require('./common');
|
||||
var _ = require('lodash');
|
||||
var LRU = require('lru-cache');
|
||||
|
||||
function AddressController(node) {
|
||||
function AddressController(node, translateAddresses) {
|
||||
this.node = node;
|
||||
this._address = this.node.services.address;
|
||||
this._block = this.node.services.block;
|
||||
this.txController = new TxController(node);
|
||||
this.common = new Common({log: this.node.log});
|
||||
this.txController = new TxController(node, translateAddresses);
|
||||
this.common = new Common({log: this.node.log, translateAddresses: translateAddresses});
|
||||
this._block = this.node.services.block;
|
||||
this._utxoCache = new LRU({
|
||||
max: 250,
|
||||
@ -37,10 +37,14 @@ AddressController.prototype.show = function(req, res) {
|
||||
}
|
||||
|
||||
this._address.getAddressSummary(req.addr, options, function(err, data) {
|
||||
|
||||
if(err) {
|
||||
return self.common.handleErrors(err, res);
|
||||
}
|
||||
|
||||
if (data && data.addrStr)
|
||||
data.addrStr = self.common.translateOutputAddress(data.addrStr);
|
||||
|
||||
|
||||
res.jsonp(data);
|
||||
});
|
||||
};
|
||||
@ -73,6 +77,7 @@ AddressController.prototype.addressSummarySubQuery = function(req, res, param) {
|
||||
};
|
||||
|
||||
AddressController.prototype.getAddressSummary = function(address, options, callback) {
|
||||
var self = this;
|
||||
|
||||
this._address.getAddressSummary(address, options, function(err, summary) {
|
||||
if(err) {
|
||||
@ -80,7 +85,7 @@ AddressController.prototype.getAddressSummary = function(address, options, callb
|
||||
}
|
||||
|
||||
var transformed = {
|
||||
addrStr: address,
|
||||
address: self.common.translateOutputAddress(address),
|
||||
balance: Unit.fromSatoshis(summary.balance).toBTC(),
|
||||
balanceSat: summary.balance,
|
||||
totalReceived: Unit.fromSatoshis(summary.totalReceived).toBTC(),
|
||||
@ -99,6 +104,7 @@ AddressController.prototype.getAddressSummary = function(address, options, callb
|
||||
};
|
||||
|
||||
AddressController.prototype.checkAddrs = function(req, res, next) {
|
||||
var self = this;
|
||||
|
||||
function makeArray(addrs) {
|
||||
if (_.isString(addrs)) {
|
||||
@ -123,29 +129,18 @@ AddressController.prototype.checkAddrs = function(req, res, next) {
|
||||
}, res);
|
||||
}
|
||||
|
||||
var inValid = this.check(req.addrs);
|
||||
|
||||
if (inValid) {
|
||||
try {
|
||||
req.addrs = self.common.translateInputAddresses(req.addrs);
|
||||
req.addr = req.addrs[0];
|
||||
} catch(e) {
|
||||
console.log('[addresses.js.130]', e); //TODO
|
||||
return this.common.handleErrors({
|
||||
message: 'Invalid address: ' + inValid.message,
|
||||
message: 'Invalid address: ' + e,
|
||||
code: 1
|
||||
}, res);
|
||||
}
|
||||
};
|
||||
|
||||
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) {
|
||||
@ -170,9 +165,11 @@ AddressController.prototype.utxo = function(req, res) {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
AddressController.prototype.transformUtxo = function(utxoArg) {
|
||||
|
||||
var utxo = {
|
||||
address: utxoArg.address,
|
||||
address: this.common.translateOutputAddress(utxoArg.address),
|
||||
txid: utxoArg.txid,
|
||||
vout: utxoArg.vout,
|
||||
scriptPubKey: utxoArg.scriptPubKey,
|
||||
@ -251,8 +248,9 @@ AddressController.prototype.multiutxo = function(req, res) {
|
||||
if (utxos.length - 1 === i) {
|
||||
sep = '';
|
||||
}
|
||||
utxos[i] = self.transformUtxo(utxos[i]);
|
||||
cache.push(utxos[i]);
|
||||
res.write(JSON.stringify(self.transformUtxo(utxos[i])) + sep);
|
||||
res.write(JSON.stringify(utxos[i]) + sep);
|
||||
}
|
||||
|
||||
sep = ',';
|
||||
|
||||
56
lib/addresstranslator.js
Normal file
56
lib/addresstranslator.js
Normal 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;
|
||||
@ -1,7 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var AddressTranslator = require('./addresstranslator');
|
||||
var bitcore = require('bitcore-lib');
|
||||
|
||||
function Common(options) {
|
||||
this.log = options.log;
|
||||
this.translateAddresses = options.translateAddresses;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -27,6 +27,7 @@ var EventEmitter = require('events').EventEmitter;
|
||||
* @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 {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) {
|
||||
BaseService.call(this, options);
|
||||
@ -47,6 +48,7 @@ var InsightAPI = function(options) {
|
||||
|
||||
this.rateLimiterOptions = options.rateLimiterOptions;
|
||||
this.disableRateLimiter = options.disableRateLimiter;
|
||||
this.translateAddresses = options.translateAddresses;
|
||||
|
||||
this.blockSummaryCacheSize = options.blockSummaryCacheSize || BlockController.DEFAULT_BLOCKSUMMARY_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));
|
||||
|
||||
// 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.param('txid', transactions.transaction.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));
|
||||
|
||||
// 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/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));
|
||||
|
||||
@ -8,9 +8,9 @@ var async = require('async');
|
||||
|
||||
var MAXINT = 0xffffffff; // Math.pow(2, 32) - 1;
|
||||
|
||||
function TxController(node) {
|
||||
function TxController(node, translateAddresses) {
|
||||
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._transaction = this.node.services.transaction;
|
||||
this._address = this.node.services.address;
|
||||
@ -134,7 +134,8 @@ TxController.prototype.transformInput = function(options, input, index) {
|
||||
var address = input.getAddress();
|
||||
if (address) {
|
||||
address.network = this._network;
|
||||
transformed.addr = address.toString();
|
||||
transformed.addr = this.common.translateOutputAddress(address.toString());
|
||||
|
||||
} else {
|
||||
transformed.addr = null;
|
||||
}
|
||||
@ -170,13 +171,16 @@ TxController.prototype.transformOutput = function(options, output, index) {
|
||||
var address = output.getAddress();
|
||||
if (address) {
|
||||
address.network = this._network;
|
||||
transformed.scriptPubKey.addresses = [address.toString()];
|
||||
transformed.scriptPubKey.addresses = [this.common.translateOutputAddress(address.toString())];
|
||||
|
||||
transformed.scriptPubKey.type = address.getType();
|
||||
}
|
||||
return transformed;
|
||||
};
|
||||
|
||||
TxController.prototype.transformInvTransaction = function(transaction) {
|
||||
var self = this;
|
||||
|
||||
var valueOut = 0;
|
||||
var vout = [];
|
||||
for (var i = 0; i < transaction.outputs.length; i++) {
|
||||
@ -190,7 +194,7 @@ TxController.prototype.transformInvTransaction = function(transaction) {
|
||||
}
|
||||
|
||||
address.network = this._network;
|
||||
address = address.toString();
|
||||
address = self.common.translateOutputAddress(address.toString());
|
||||
|
||||
var obj = {};
|
||||
obj[address] = output.value;
|
||||
@ -244,7 +248,7 @@ TxController.prototype.list = function(req, res) {
|
||||
var self = this;
|
||||
|
||||
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 pageLength = 10;
|
||||
var pagesTotal = 1;
|
||||
|
||||
60
package-lock.json
generated
60
package-lock.json
generated
@ -80,6 +80,14 @@
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"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": {
|
||||
"version": "0.1.5",
|
||||
"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": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bitcore-message/-/bitcore-message-1.0.2.tgz",
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
"async": "*",
|
||||
"bcoin": "bcoin-org/bcoin#886008a1822ce1da7fa8395ee7db4bcc1750a28a",
|
||||
"bitcore-lib": "5.0.0-beta.1",
|
||||
"bitcore-lib-cash": "0.15.1",
|
||||
"bitcore-message": "^1.0.1",
|
||||
"body-parser": "^1.13.3",
|
||||
"compression": "^1.6.1",
|
||||
|
||||
306
test/addressesCash.js
Normal file
306
test/addressesCash.js
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
53
test/addressestranslator.js
Normal file
53
test/addressestranslator.js
Normal 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');
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user