Add Insight and UTXO class
This commit is contained in:
parent
9f32c1b7ba
commit
476f009b4d
4
index.js
4
index.js
|
@ -53,5 +53,9 @@ bitcore.deps.bs58 = require('bs58');
|
|||
bitcore.deps.Buffer = Buffer;
|
||||
bitcore.deps.elliptic = require('elliptic');
|
||||
|
||||
// blockchain explorers
|
||||
bitcore.explorers = {};
|
||||
bitcore.explorers.Insight = require('./lib/explorers/insight');
|
||||
|
||||
// Internal usage, exposed for testing/advanced tweaking
|
||||
bitcore._HDKeyCache = require('./lib/hdkeycache');
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
'use strict';
|
||||
|
||||
var Networks = require('../networks');
|
||||
var JSUtil = require('../util/js');
|
||||
var $ = require('../util/preconditions');
|
||||
var _ = require('lodash');
|
||||
var Address = require('../address');
|
||||
var Transaction = require('../transaction');
|
||||
var UTXO = require('../utxo');
|
||||
|
||||
var request = require('request');
|
||||
|
||||
// var insight = new Insight(Networks.livenet);
|
||||
|
||||
function Insight(url, network) {
|
||||
if (!url && !network) {
|
||||
return new Insight(Networks.defaultNetwork);
|
||||
}
|
||||
if (Networks.get(url)) {
|
||||
network = Networks.get(url);
|
||||
if (network === Networks.livenet) {
|
||||
url = 'https://insight.bitpay.com';
|
||||
} else {
|
||||
url = 'https://test-insight.bitpay.com';
|
||||
}
|
||||
}
|
||||
JSUtil.defineImmutable(this, {
|
||||
url: url,
|
||||
network: Networks.get(network) || Networks.defaultNetwork
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
Insight.prototype.getUnspentUtxos = function(addresses, callback) {
|
||||
$.checkArgument(_.isFunction(callback));
|
||||
if (!_.isArray(addresses)) {
|
||||
addresses = [addresses];
|
||||
}
|
||||
addresses = _.map(addresses, function(address) { return new Address(address); });
|
||||
|
||||
this.requestPost('/api/addrs/utxo', {
|
||||
addrs: _.map(addresses, function(address) { return address.toString(); }).join(',')
|
||||
}, function(err, res, unspent) {
|
||||
if (err || res.statusCode !== 200) {
|
||||
return callback(err || res);
|
||||
}
|
||||
unspent = _.map(unspent, UTXO);
|
||||
|
||||
return callback(null, unspent);
|
||||
});
|
||||
};
|
||||
|
||||
Insight.prototype.broadcast = function(transaction, callback) {
|
||||
$.checkArgument(JSUtil.isHexa(transaction) || transaction instanceof Transaction);
|
||||
$.checkArgument(_.isFunction(callback));
|
||||
if (transaction instanceof Transaction) {
|
||||
transaction = transaction.serialize();
|
||||
}
|
||||
|
||||
this.requestPost('/api/tx/send', {
|
||||
rawtx: transaction
|
||||
}, function(err, res, body) {
|
||||
if (err || res.statusCode !== 200) {
|
||||
return callback(err || body);
|
||||
}
|
||||
return callback(null, body ? body.txid : null);
|
||||
});
|
||||
};
|
||||
|
||||
Insight.prototype.requestPost = function(path, data, callback) {
|
||||
$.checkArgument(_.isString(path));
|
||||
$.checkArgument(_.isFunction(callback));
|
||||
request({
|
||||
method: 'POST',
|
||||
url: this.url + path,
|
||||
json: data
|
||||
}, callback);
|
||||
};
|
||||
|
||||
module.exports = Insight;
|
|
@ -15,7 +15,7 @@ var Signature = require('../crypto/signature');
|
|||
var Sighash = require('./sighash');
|
||||
|
||||
var Address = require('../address');
|
||||
var Unit = require('../unit');
|
||||
var UTXO = require('../utxo');
|
||||
var Input = require('./input');
|
||||
var PublicKeyHashInput = Input.PublicKeyHash;
|
||||
var MultiSigScriptHashInput = Input.MultiSigScriptHash;
|
||||
|
@ -293,68 +293,23 @@ Transaction.prototype._newTransaction = function() {
|
|||
* @param {number=} threshold
|
||||
*/
|
||||
Transaction.prototype.from = function(utxo, pubkeys, threshold) {
|
||||
if (_.isArray(utxo)) {
|
||||
var self = this;
|
||||
_.each(utxo, function(utxo) {
|
||||
self.from(utxo, pubkeys, threshold);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
if (pubkeys && threshold) {
|
||||
this._fromMultiSigP2SH(utxo, pubkeys, threshold);
|
||||
this._fromMultisigUtxo(utxo, pubkeys, threshold);
|
||||
} else {
|
||||
this._fromNonP2SH(utxo);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Transaction.prototype._fromMultiSigP2SH = function(utxo, pubkeys, threshold) {
|
||||
if (Transaction._isNewUtxo(utxo)) {
|
||||
this._fromMultisigNewUtxo(utxo, pubkeys, threshold);
|
||||
} else if (Transaction._isOldUtxo(utxo)) {
|
||||
this._fromMultisigOldUtxo(utxo, pubkeys, threshold);
|
||||
} else {
|
||||
throw new Transaction.Errors.UnrecognizedUtxoFormat(utxo);
|
||||
}
|
||||
};
|
||||
|
||||
Transaction.prototype._fromNonP2SH = function(utxo) {
|
||||
var self = this;
|
||||
if (_.isArray(utxo)) {
|
||||
_.each(utxo, function(single) {
|
||||
self._fromNonP2SH(single);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (Transaction._isNewUtxo(utxo)) {
|
||||
this._fromNewUtxo(utxo);
|
||||
} else if (Transaction._isOldUtxo(utxo)) {
|
||||
this._fromOldUtxo(utxo);
|
||||
} else {
|
||||
throw new Transaction.Errors.UnrecognizedUtxoFormat(utxo);
|
||||
}
|
||||
};
|
||||
|
||||
Transaction._isNewUtxo = function(utxo) {
|
||||
var isDefined = function(param) {
|
||||
return !_.isUndefined(param);
|
||||
};
|
||||
return _.all(_.map([utxo.txId, utxo.outputIndex, utxo.satoshis, utxo.script], isDefined));
|
||||
};
|
||||
|
||||
Transaction._isOldUtxo = function(utxo) {
|
||||
var isDefined = function(param) {
|
||||
return !_.isUndefined(param);
|
||||
};
|
||||
return _.all(_.map([utxo.txid, utxo.vout, utxo.scriptPubKey, utxo.amount], isDefined));
|
||||
};
|
||||
|
||||
Transaction.prototype._fromOldUtxo = function(utxo) {
|
||||
return this._fromNewUtxo({
|
||||
address: utxo.address && new Address(utxo.address),
|
||||
txId: utxo.txid,
|
||||
outputIndex: utxo.vout,
|
||||
script: util.isHexa(utxo.script) ? new buffer.Buffer(utxo.scriptPubKey, 'hex') : utxo.scriptPubKey,
|
||||
satoshis: Unit.fromBTC(utxo.amount).satoshis
|
||||
});
|
||||
};
|
||||
|
||||
Transaction.prototype._fromNewUtxo = function(utxo) {
|
||||
utxo.address = utxo.address && new Address(utxo.address);
|
||||
utxo.script = new Script(util.isHexa(utxo.script) ? new buffer.Buffer(utxo.script, 'hex') : utxo.script);
|
||||
utxo = new UTXO(utxo);
|
||||
this.inputs.push(new PublicKeyHashInput({
|
||||
output: new Output({
|
||||
script: utxo.script,
|
||||
|
@ -368,19 +323,8 @@ Transaction.prototype._fromNewUtxo = function(utxo) {
|
|||
this._inputAmount += utxo.satoshis;
|
||||
};
|
||||
|
||||
Transaction.prototype._fromMultisigOldUtxo = function(utxo, pubkeys, threshold) {
|
||||
return this._fromMultisigNewUtxo({
|
||||
address: utxo.address && new Address(utxo.address),
|
||||
txId: utxo.txid,
|
||||
outputIndex: utxo.vout,
|
||||
script: new buffer.Buffer(utxo.scriptPubKey, 'hex'),
|
||||
satoshis: Unit.fromBTC(utxo.amount).satoshis
|
||||
}, pubkeys, threshold);
|
||||
};
|
||||
|
||||
Transaction.prototype._fromMultisigNewUtxo = function(utxo, pubkeys, threshold) {
|
||||
utxo.address = utxo.address && new Address(utxo.address);
|
||||
utxo.script = new Script(util.isHexa(utxo.script) ? new buffer.Buffer(utxo.script, 'hex') : utxo.script);
|
||||
Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) {
|
||||
utxo = new UTXO(utxo);
|
||||
this.addInput(new MultiSigScriptHashInput({
|
||||
output: new Output({
|
||||
script: utxo.script,
|
||||
|
|
|
@ -55,6 +55,7 @@ module.exports = {
|
|||
Object.keys(values).forEach(function(key){
|
||||
Object.defineProperty(target, key, {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
value: values[key]
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var $ = require('./util/preconditions');
|
||||
var JSUtil = require('./util/js');
|
||||
|
||||
var Script = require('./script');
|
||||
var Address = require('./address');
|
||||
var Unit = require('./unit');
|
||||
|
||||
function UTXO(data) {
|
||||
/* jshint maxcomplexity: 20 */
|
||||
/* jshint maxstatements: 20 */
|
||||
if (!(this instanceof UTXO)) {
|
||||
return new UTXO(data);
|
||||
}
|
||||
$.checkArgument(_.isObject(data), 'Must provide an object from where to extract data');
|
||||
var address = data.address ? new Address(data.address) : undefined;
|
||||
var txId = data.txid ? data.txid : data.txId;
|
||||
if (!txId || !JSUtil.isHexaString(txId) || txId.length > 64) {
|
||||
// TODO: Use the errors library
|
||||
throw new Error('Invalid TXID in object', data);
|
||||
}
|
||||
var outputIndex = _.isUndefined(data.vout) ? data.outputIndex : data.vout;
|
||||
if (!_.isNumber(outputIndex)) {
|
||||
throw new Error('Invalid outputIndex, received ' + outputIndex);
|
||||
}
|
||||
$.checkArgument(data.scriptPubKey || data.script, 'Must provide the scriptPubKey for that output!');
|
||||
var script = new Script(data.scriptPubKey || data.script);
|
||||
$.checkArgument(data.amount || data.satoshis, 'Must provide the scriptPubKey for that output!');
|
||||
var amount = data.amount ? new Unit.fromBTC(data.amount).toSatoshis() : data.satoshis;
|
||||
$.checkArgument(_.isNumber(amount), 'Amount must be a number');
|
||||
JSUtil.defineImmutable(this, {
|
||||
address: address,
|
||||
txId: txId,
|
||||
outputIndex: outputIndex,
|
||||
script: script,
|
||||
satoshis: amount
|
||||
});
|
||||
}
|
||||
|
||||
UTXO.prototype.inspect = function() {
|
||||
return '<UTXO: ' + this.txId + ':' + this.outputIndex +
|
||||
', satoshis: ' + this.satoshis + ', address: ' + this.address + '>';
|
||||
};
|
||||
|
||||
UTXO.prototype.toString = function() {
|
||||
return this.txId + ':' + this.outputIndex;
|
||||
};
|
||||
|
||||
UTXO.fromJSON = UTXO.fromObject = function(data) {
|
||||
if (_.isString(data)) {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
return new UTXO(data);
|
||||
};
|
||||
|
||||
UTXO.prototype.toJSON = function() {
|
||||
return JSON.stringify(this.toObject());
|
||||
};
|
||||
|
||||
UTXO.prototype.toObject = function() {
|
||||
return {
|
||||
address: this.address.toObject(),
|
||||
txid: this.txId,
|
||||
vout: this.outputIndex,
|
||||
scriptPubKey: this.script.toObject(),
|
||||
amount: Unit.fromSatoshis(this.satoshis).toBTC()
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = UTXO;
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bitcore",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.5",
|
||||
"dependencies": {
|
||||
"aes": {
|
||||
"version": "0.1.0",
|
||||
|
@ -17,6 +17,11 @@
|
|||
"from": "bn.js@0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-0.16.0.tgz"
|
||||
},
|
||||
"browser-request": {
|
||||
"version": "0.3.3",
|
||||
"from": "browser-request@*",
|
||||
"resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz"
|
||||
},
|
||||
"bs58": {
|
||||
"version": "2.0.0",
|
||||
"from": "bs58@2.0.0",
|
||||
|
@ -89,6 +94,11 @@
|
|||
"from": "protobufjs@3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-3.0.0.tgz"
|
||||
},
|
||||
"request": {
|
||||
"version": "2.51.0",
|
||||
"from": "request@*",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.51.0.tgz"
|
||||
},
|
||||
"sha512": {
|
||||
"version": "0.0.1",
|
||||
"from": "sha512@=0.0.1",
|
||||
|
|
|
@ -69,9 +69,13 @@
|
|||
"type": "git",
|
||||
"url": "https://github.com/bitpay/bitcore.git"
|
||||
},
|
||||
"browser": {
|
||||
"request": "browser-request"
|
||||
},
|
||||
"dependencies": {
|
||||
"asn1.js": "=0.4.1",
|
||||
"bn.js": "=0.16.0",
|
||||
"browser-request": "^0.3.3",
|
||||
"bs58": "=2.0.0",
|
||||
"bufferput": "^0.1.2",
|
||||
"buffers": "^0.1.1",
|
||||
|
@ -81,6 +85,7 @@
|
|||
"jsrsasign": "=0.0.3",
|
||||
"lodash": "=2.4.1",
|
||||
"protobufjs": "=3.0.0",
|
||||
"request": "^2.51.0",
|
||||
"sha512": "=0.0.1",
|
||||
"socks5-client": "^0.3.6"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue