Skip to content
This repository has been archived by the owner on Apr 3, 2019. It is now read-only.

Commit

Permalink
Merge pull request #731 from matiu/feat/addr-translate
Browse files Browse the repository at this point in the history
Feat/addr translate
  • Loading branch information
matiu committed Nov 14, 2017
2 parents 3718493 + 89ab474 commit a62cb3d
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 7 deletions.
56 changes: 56 additions & 0 deletions lib/addresstranslator.js
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions lib/blockchainexplorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function BlockChainExplorer(opts) {
url: url,
apiPrefix: opts.apiPrefix,
userAgent: opts.userAgent,
translateAddresses: opts.translateAddresses,
});
default:
throw new Error('Provider ' + provider + ' not supported.');
Expand Down
80 changes: 73 additions & 7 deletions lib/blockchainexplorers/insight.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ log.debug = log.verbose;
var io = require('socket.io-client');
var requestList = require('./request-list');
var Common = require('../common');
var AddressTranslator = require('../addresstranslator');
var Constants = Common.Constants,
Defaults = Common.Defaults,
Utils = Common.Utils;
Expand All @@ -18,14 +19,16 @@ function Insight(opts) {
$.checkArgument(Utils.checkValueInCollection(opts.coin, Constants.COINS));
$.checkArgument(opts.url);

this.apiPrefix = opts.apiPrefix || '/api';
this.apiPrefix = _.isUndefined(opts.apiPrefix)? '/api' : opts.apiPrefix;
this.coin = opts.coin || Defaults.COIN;
this.network = opts.network || 'livenet';
this.hosts = opts.url;
this.userAgent = opts.userAgent || 'bws';
this.shouldTranslateAddresses = _.isUndefined(opts.translateAddresses) ? this.coin == 'bch' : opts.translateAddresses;

this.requestQueue = async.queue(this._doRequest.bind(this), Defaults.INSIGHT_REQUEST_POOL_SIZE);
}

}

var _parseErr = function(err, res) {
if (err) {
Expand All @@ -36,6 +39,46 @@ var _parseErr = function(err, res) {
return "Error querying the blockchain";
};


// Translate Request Address query
Insight.prototype.translateQueryAddresses = function(addresses) {
if (!this.shouldTranslateAddresses) return addresses;

// It is called 'translatedInput' from Cxxx to 1xxx because the
// module was created for insight-api
return AddressTranslator.translateInput(addresses);
};


// Translate Result Address
Insight.prototype.translateResultAddresses = function(addresses) {
if (!this.shouldTranslateAddresses) return addresses;

// It is called 'translateOutput' from 1xxx to Cxxx because the
// module was created for insight-api
return AddressTranslator.translateOutput(addresses);
};


Insight.prototype.translateTx = function(tx) {
if (!this.shouldTranslateAddresses) return tx;

_.each(tx.input, function(x){
if (x.addr) {
x.addr = AddressTranslator.translateOutput(x.addr);
}
});


_.each(tx.output, function(x){
if (x.scriptPubKey && x.scriptPubKey.addresses) {
x.scriptPubKey.addresses = AddressTranslator.translateOutput(x.scriptPubKey.addresses);
}
});

};


Insight.prototype._doRequest = function(args, cb) {
var opts = {
hosts: this.hosts,
Expand All @@ -45,9 +88,10 @@ Insight.prototype._doRequest = function(args, cb) {
};

var s = JSON.stringify(args);
if ( s.length > 100 )
s= s.substr(0,100) + '...';
// if ( s.length > 100 )
// s= s.substr(0,100) + '...';
log.debug('', 'Insight Q: %s', s);

requestList(_.defaults(args, opts), cb);
};

Expand All @@ -59,17 +103,25 @@ Insight.prototype.getConnectionInfo = function() {
* Retrieve a list of unspent outputs associated with an address or set of addresses
*/
Insight.prototype.getUtxos = function(addresses, cb) {
var self = this;

var url = this.url + this.apiPrefix + '/addrs/utxo';
var args = {
method: 'POST',
path: this.apiPrefix + '/addrs/utxo',
json: {
addrs: _.uniq([].concat(addresses)).join(',')
addrs: this.translateQueryAddresses(_.uniq([].concat(addresses))).join(',')
},
};

this.requestQueue.push(args, function(err, res, unspent) {
if (err || res.statusCode !== 200) return cb(_parseErr(err, res));

if (self.shouldTranslateAddresses) {
_.each(unspent, function(x) {
x.address = self.translateResultAddresses(x.address);
});
}
return cb(null, unspent);
});
};
Expand All @@ -93,6 +145,7 @@ Insight.prototype.broadcast = function(rawTx, cb) {
};

Insight.prototype.getTransaction = function(txid, cb) {
var self = this;
var args = {
method: 'GET',
path: this.apiPrefix + '/tx/' + txid,
Expand All @@ -104,11 +157,16 @@ Insight.prototype.getTransaction = function(txid, cb) {
if (err || res.statusCode !== 200)
return cb(_parseErr(err, res));

self.translateTx(tx);

return cb(null, tx);
});
};

Insight.prototype.getTransactions = function(addresses, from, to, cb) {
var self = this;


var qs = [];
var total;
if (_.isNumber(from)) qs.push('from=' + from);
Expand All @@ -123,7 +181,7 @@ Insight.prototype.getTransactions = function(addresses, from, to, cb) {
method: 'POST',
path: this.apiPrefix + '/addrs/txs' + (qs.length > 0 ? '?' + qs.join('&') : ''),
json: {
addrs: _.uniq([].concat(addresses)).join(',')
addrs: this.translateQueryAddresses(_.uniq([].concat(addresses))).join(',')
},
timeout: 120000,
};
Expand All @@ -143,6 +201,12 @@ Insight.prototype.getTransactions = function(addresses, from, to, cb) {
// NOTE: Whenever Insight breaks communication with bitcoind, it returns invalid data but no error code.
if (!_.isArray(txs) || (txs.length != _.compact(txs).length)) return cb(new Error('Could not retrieve transactions from blockchain. Request was:' + JSON.stringify(args)));

if (self.shouldTranslateAddresses) {
_.each(txs, function(tx){
self.translateTx(tx);
});
}

return cb(null, txs, total);
});
};
Expand All @@ -152,7 +216,7 @@ Insight.prototype.getAddressActivity = function(address, cb) {

var args = {
method: 'GET',
path: self.apiPrefix + '/addr/' + address,
path: self.apiPrefix + '/addr/' + this.translateQueryAddresses(address),
json: true,
};

Expand All @@ -161,6 +225,8 @@ Insight.prototype.getAddressActivity = function(address, cb) {
if (err || res.statusCode !== 200)
return cb(_parseErr(err, res));

// note: result.addrStr is not translated, but not used.

var nbTxs = result.unconfirmedTxApperances + result.txApperances;
return cb(null, nbTxs > 0);
});
Expand Down
1 change: 1 addition & 0 deletions lib/blockchainexplorers/request-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ var requestList = function(args, cb) {
}

result = [err, res, body];
console.log('[request-list.js.62:body:]',body); //TODO
return a_cb();
});
},
Expand Down
53 changes: 53 additions & 0 deletions test/addressestranslator.js
Original file line number Diff line number Diff line change
@@ -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');
});


});


0 comments on commit a62cb3d

Please sign in to comment.