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.Buffer = Buffer;
|
||||||
bitcore.deps.elliptic = require('elliptic');
|
bitcore.deps.elliptic = require('elliptic');
|
||||||
|
|
||||||
|
// blockchain explorers
|
||||||
|
bitcore.explorers = {};
|
||||||
|
bitcore.explorers.Insight = require('./lib/explorers/insight');
|
||||||
|
|
||||||
// Internal usage, exposed for testing/advanced tweaking
|
// Internal usage, exposed for testing/advanced tweaking
|
||||||
bitcore._HDKeyCache = require('./lib/hdkeycache');
|
bitcore._HDKeyCache = require('./lib/hdkeycache');
|
||||||
|
|||||||
80
lib/explorers/insight.js
Normal file
80
lib/explorers/insight.js
Normal file
@ -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 Sighash = require('./sighash');
|
||||||
|
|
||||||
var Address = require('../address');
|
var Address = require('../address');
|
||||||
var Unit = require('../unit');
|
var UTXO = require('../utxo');
|
||||||
var Input = require('./input');
|
var Input = require('./input');
|
||||||
var PublicKeyHashInput = Input.PublicKeyHash;
|
var PublicKeyHashInput = Input.PublicKeyHash;
|
||||||
var MultiSigScriptHashInput = Input.MultiSigScriptHash;
|
var MultiSigScriptHashInput = Input.MultiSigScriptHash;
|
||||||
@ -293,68 +293,23 @@ Transaction.prototype._newTransaction = function() {
|
|||||||
* @param {number=} threshold
|
* @param {number=} threshold
|
||||||
*/
|
*/
|
||||||
Transaction.prototype.from = function(utxo, pubkeys, 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) {
|
if (pubkeys && threshold) {
|
||||||
this._fromMultiSigP2SH(utxo, pubkeys, threshold);
|
this._fromMultisigUtxo(utxo, pubkeys, threshold);
|
||||||
} else {
|
} else {
|
||||||
this._fromNonP2SH(utxo);
|
this._fromNonP2SH(utxo);
|
||||||
}
|
}
|
||||||
return this;
|
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) {
|
Transaction.prototype._fromNonP2SH = function(utxo) {
|
||||||
var self = this;
|
utxo = new UTXO(utxo);
|
||||||
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);
|
|
||||||
this.inputs.push(new PublicKeyHashInput({
|
this.inputs.push(new PublicKeyHashInput({
|
||||||
output: new Output({
|
output: new Output({
|
||||||
script: utxo.script,
|
script: utxo.script,
|
||||||
@ -368,19 +323,8 @@ Transaction.prototype._fromNewUtxo = function(utxo) {
|
|||||||
this._inputAmount += utxo.satoshis;
|
this._inputAmount += utxo.satoshis;
|
||||||
};
|
};
|
||||||
|
|
||||||
Transaction.prototype._fromMultisigOldUtxo = function(utxo, pubkeys, threshold) {
|
Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) {
|
||||||
return this._fromMultisigNewUtxo({
|
utxo = new UTXO(utxo);
|
||||||
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);
|
|
||||||
this.addInput(new MultiSigScriptHashInput({
|
this.addInput(new MultiSigScriptHashInput({
|
||||||
output: new Output({
|
output: new Output({
|
||||||
script: utxo.script,
|
script: utxo.script,
|
||||||
|
|||||||
@ -55,6 +55,7 @@ module.exports = {
|
|||||||
Object.keys(values).forEach(function(key){
|
Object.keys(values).forEach(function(key){
|
||||||
Object.defineProperty(target, key, {
|
Object.defineProperty(target, key, {
|
||||||
configurable: false,
|
configurable: false,
|
||||||
|
enumerable: true,
|
||||||
value: values[key]
|
value: values[key]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
72
lib/utxo.js
Normal file
72
lib/utxo.js
Normal file
@ -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;
|
||||||
12
npm-shrinkwrap.json
generated
12
npm-shrinkwrap.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bitcore",
|
"name": "bitcore",
|
||||||
"version": "0.8.0",
|
"version": "0.8.5",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aes": {
|
"aes": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@ -17,6 +17,11 @@
|
|||||||
"from": "bn.js@0.16.0",
|
"from": "bn.js@0.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-0.16.0.tgz"
|
"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": {
|
"bs58": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"from": "bs58@2.0.0",
|
"from": "bs58@2.0.0",
|
||||||
@ -89,6 +94,11 @@
|
|||||||
"from": "protobufjs@3.0.0",
|
"from": "protobufjs@3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-3.0.0.tgz"
|
"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": {
|
"sha512": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"from": "sha512@=0.0.1",
|
"from": "sha512@=0.0.1",
|
||||||
|
|||||||
@ -69,9 +69,13 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/bitpay/bitcore.git"
|
"url": "https://github.com/bitpay/bitcore.git"
|
||||||
},
|
},
|
||||||
|
"browser": {
|
||||||
|
"request": "browser-request"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asn1.js": "=0.4.1",
|
"asn1.js": "=0.4.1",
|
||||||
"bn.js": "=0.16.0",
|
"bn.js": "=0.16.0",
|
||||||
|
"browser-request": "^0.3.3",
|
||||||
"bs58": "=2.0.0",
|
"bs58": "=2.0.0",
|
||||||
"bufferput": "^0.1.2",
|
"bufferput": "^0.1.2",
|
||||||
"buffers": "^0.1.1",
|
"buffers": "^0.1.1",
|
||||||
@ -81,6 +85,7 @@
|
|||||||
"jsrsasign": "=0.0.3",
|
"jsrsasign": "=0.0.3",
|
||||||
"lodash": "=2.4.1",
|
"lodash": "=2.4.1",
|
||||||
"protobufjs": "=3.0.0",
|
"protobufjs": "=3.0.0",
|
||||||
|
"request": "^2.51.0",
|
||||||
"sha512": "=0.0.1",
|
"sha512": "=0.0.1",
|
||||||
"socks5-client": "^0.3.6"
|
"socks5-client": "^0.3.6"
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user