You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
5.5 KiB
216 lines
5.5 KiB
'use strict';
|
|
|
|
var _ = require('lodash');
|
|
var $ = require('preconditions').singleton();
|
|
var log = require('npmlog');
|
|
log.debug = log.verbose;
|
|
var io = require('socket.io-client');
|
|
var requestList = require('./request-list');
|
|
var Common = require('../common');
|
|
var Constants = Common.Constants,
|
|
Defaults = Common.Defaults,
|
|
Utils = Common.Utils;
|
|
|
|
function Insight(opts) {
|
|
$.checkArgument(opts);
|
|
$.checkArgument(Utils.checkValueInCollection(opts.network, Constants.NETWORKS));
|
|
$.checkArgument(Utils.checkValueInCollection(opts.coin, Constants.COINS));
|
|
$.checkArgument(opts.url);
|
|
|
|
this.apiPrefix = opts.apiPrefix || '/api';
|
|
this.coin = opts.coin || Defaults.COIN;
|
|
this.network = opts.network || 'livenet';
|
|
this.hosts = opts.url;
|
|
this.userAgent = opts.userAgent || 'bws';
|
|
};
|
|
|
|
|
|
var _parseErr = function(err, res) {
|
|
if (err) {
|
|
log.warn('Insight error: ', err);
|
|
return "Insight Error";
|
|
}
|
|
log.warn("Insight " + res.request.href + " Returned Status: " + res.statusCode);
|
|
return "Error querying the blockchain";
|
|
};
|
|
|
|
Insight.prototype._doRequest = function(args, cb) {
|
|
var opts = {
|
|
hosts: this.hosts,
|
|
headers: {
|
|
'User-Agent': this.userAgent,
|
|
}
|
|
};
|
|
requestList(_.defaults(args, opts), cb);
|
|
};
|
|
|
|
Insight.prototype.getConnectionInfo = function() {
|
|
return 'Insight (' + this.coin + '/' + this.network + ') @ ' + this.hosts;
|
|
};
|
|
|
|
/**
|
|
* Retrieve a list of unspent outputs associated with an address or set of addresses
|
|
*/
|
|
Insight.prototype.getUtxos = function(addresses, cb) {
|
|
var url = this.url + this.apiPrefix + '/addrs/utxo';
|
|
var args = {
|
|
method: 'POST',
|
|
path: this.apiPrefix + '/addrs/utxo',
|
|
json: {
|
|
addrs: _.uniq([].concat(addresses)).join(',')
|
|
},
|
|
};
|
|
|
|
this._doRequest(args, function(err, res, unspent) {
|
|
if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
|
|
return cb(null, unspent);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Broadcast a transaction to the bitcoin network
|
|
*/
|
|
Insight.prototype.broadcast = function(rawTx, cb) {
|
|
var args = {
|
|
method: 'POST',
|
|
path: this.apiPrefix + '/tx/send',
|
|
json: {
|
|
rawtx: rawTx
|
|
},
|
|
};
|
|
|
|
this._doRequest(args, function(err, res, body) {
|
|
if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
|
|
return cb(null, body ? body.txid : null);
|
|
});
|
|
};
|
|
|
|
Insight.prototype.getTransaction = function(txid, cb) {
|
|
var args = {
|
|
method: 'GET',
|
|
path: this.apiPrefix + '/tx/' + txid,
|
|
json: true,
|
|
};
|
|
|
|
this._doRequest(args, function(err, res, tx) {
|
|
if (res && res.statusCode == 404) return cb();
|
|
if (err || res.statusCode !== 200)
|
|
return cb(_parseErr(err, res));
|
|
|
|
return cb(null, tx);
|
|
});
|
|
};
|
|
|
|
Insight.prototype.getTransactions = function(addresses, from, to, cb) {
|
|
var qs = [];
|
|
var total;
|
|
if (_.isNumber(from)) qs.push('from=' + from);
|
|
if (_.isNumber(to)) qs.push('to=' + to);
|
|
|
|
// Trim output
|
|
qs.push('noAsm=1');
|
|
qs.push('noScriptSig=1');
|
|
qs.push('noSpent=1');
|
|
|
|
var args = {
|
|
method: 'POST',
|
|
path: this.apiPrefix + '/addrs/txs' + (qs.length > 0 ? '?' + qs.join('&') : ''),
|
|
json: {
|
|
addrs: _.uniq([].concat(addresses)).join(',')
|
|
},
|
|
timeout: 120000,
|
|
};
|
|
|
|
this._doRequest(args, function(err, res, txs) {
|
|
if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
|
|
|
|
if (_.isObject(txs)) {
|
|
if (txs.totalItems)
|
|
total = txs.totalItems;
|
|
|
|
if (txs.items)
|
|
txs = txs.items;
|
|
}
|
|
|
|
// 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)));
|
|
|
|
return cb(null, txs, total);
|
|
});
|
|
};
|
|
|
|
Insight.prototype.getAddressActivity = function(address, cb) {
|
|
var self = this;
|
|
|
|
var args = {
|
|
method: 'GET',
|
|
path: self.apiPrefix + '/addr/' + address,
|
|
json: true,
|
|
};
|
|
|
|
this._doRequest(args, function(err, res, result) {
|
|
if (res && res.statusCode == 404) return cb();
|
|
if (err || res.statusCode !== 200)
|
|
return cb(_parseErr(err, res));
|
|
|
|
var nbTxs = result.unconfirmedTxApperances + result.txApperances;
|
|
return cb(null, nbTxs > 0);
|
|
});
|
|
};
|
|
|
|
Insight.prototype.estimateFee = function(nbBlocks, cb) {
|
|
var path = this.apiPrefix + '/utils/estimatefee';
|
|
if (nbBlocks) {
|
|
path += '?nbBlocks=' + [].concat(nbBlocks).join(',');
|
|
}
|
|
|
|
var args = {
|
|
method: 'GET',
|
|
path: path,
|
|
json: true,
|
|
};
|
|
this._doRequest(args, function(err, res, body) {
|
|
if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
|
|
return cb(null, body);
|
|
});
|
|
};
|
|
|
|
Insight.prototype.getBlockchainHeight = function(cb) {
|
|
var path = this.apiPrefix + '/sync';
|
|
|
|
var args = {
|
|
method: 'GET',
|
|
path: path,
|
|
json: true,
|
|
};
|
|
this._doRequest(args, function(err, res, body) {
|
|
if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
|
|
return cb(null, body.blockChainHeight);
|
|
});
|
|
};
|
|
|
|
Insight.prototype.getTxidsInBlock = function(blockHash, cb) {
|
|
var self = this;
|
|
|
|
var args = {
|
|
method: 'GET',
|
|
path: this.apiPrefix + '/block/' + blockHash,
|
|
json: true,
|
|
};
|
|
|
|
this._doRequest(args, function(err, res, body) {
|
|
if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
|
|
return cb(null, body.tx);
|
|
});
|
|
};
|
|
|
|
Insight.prototype.initSocket = function() {
|
|
|
|
// sockets always use the first server on the pull
|
|
var socket = io.connect(_.first([].concat(this.hosts)), {
|
|
'reconnection': true,
|
|
});
|
|
return socket;
|
|
};
|
|
|
|
module.exports = Insight;
|
|
|