Merge pull request #1151 from maraoz/address/script
refactor Address<->Script relation
This commit is contained in:
commit
a67fa91ca9
|
@ -2,10 +2,13 @@
|
|||
|
||||
var _ = require('lodash');
|
||||
var $ = require('./util/preconditions');
|
||||
var errors = require('./errors');
|
||||
var Base58Check = require('./encoding/base58check');
|
||||
var Networks = require('./networks');
|
||||
var Hash = require('./crypto/hash');
|
||||
var JSUtil = require('./util/js');
|
||||
var Script = require('./script');
|
||||
var PublicKey = require('./publickey');
|
||||
|
||||
/**
|
||||
* Instantiate an address from an address String or Buffer, a public key or script hash Buffer,
|
||||
|
@ -91,8 +94,6 @@ function Address(data, network, type) {
|
|||
* @returns {Object} An "info" object with "type", "network", and "hashBuffer"
|
||||
*/
|
||||
Address.prototype._classifyArguments = function(data, network, type) {
|
||||
var PublicKey = require('./publickey');
|
||||
var Script = require('./script');
|
||||
/* jshint maxcomplexity: 10 */
|
||||
// transform and validate input data
|
||||
if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 20) {
|
||||
|
@ -122,7 +123,7 @@ Address.PayToScriptHash = 'scripthash';
|
|||
* @returns {Object} An object with keys: hashBuffer
|
||||
* @private
|
||||
*/
|
||||
Address._transformHash = function(hash){
|
||||
Address._transformHash = function(hash) {
|
||||
var info = {};
|
||||
if (!(hash instanceof Buffer) && !(hash instanceof Uint8Array)) {
|
||||
throw new TypeError('Address supplied is not a buffer.');
|
||||
|
@ -159,7 +160,7 @@ Address._transformObject = function(data) {
|
|||
* @returns {Object} An object with keys: network and type
|
||||
* @private
|
||||
*/
|
||||
Address._classifyFromVersion = function(buffer){
|
||||
Address._classifyFromVersion = function(buffer) {
|
||||
var version = {};
|
||||
version.network = Networks.get(buffer[0]);
|
||||
switch (buffer[0]) { // the version byte
|
||||
|
@ -191,7 +192,7 @@ Address._classifyFromVersion = function(buffer){
|
|||
* @returns {Object} An object with keys: hashBuffer, network and type
|
||||
* @private
|
||||
*/
|
||||
Address._transformBuffer = function(buffer, network, type){
|
||||
Address._transformBuffer = function(buffer, network, type) {
|
||||
/* jshint maxcomplexity: 9 */
|
||||
var info = {};
|
||||
if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) {
|
||||
|
@ -208,7 +209,7 @@ Address._transformBuffer = function(buffer, network, type){
|
|||
throw new TypeError('Address has mismatched network type.');
|
||||
}
|
||||
|
||||
if (!bufferVersion.type || ( type && type !== bufferVersion.type )) {
|
||||
if (!bufferVersion.type || (type && type !== bufferVersion.type)) {
|
||||
throw new TypeError('Address has mismatched type.');
|
||||
}
|
||||
|
||||
|
@ -225,8 +226,7 @@ Address._transformBuffer = function(buffer, network, type){
|
|||
* @returns {Object} An object with keys: hashBuffer, type
|
||||
* @private
|
||||
*/
|
||||
Address._transformPublicKey = function(pubkey){
|
||||
var PublicKey = require('./publickey');
|
||||
Address._transformPublicKey = function(pubkey) {
|
||||
var info = {};
|
||||
if (!(pubkey instanceof PublicKey)) {
|
||||
throw new TypeError('Address must be an instance of PublicKey.');
|
||||
|
@ -243,23 +243,12 @@ Address._transformPublicKey = function(pubkey){
|
|||
* @returns {Object} An object with keys: hashBuffer, type
|
||||
* @private
|
||||
*/
|
||||
Address._transformScript = function(script, network){
|
||||
var Script = require('./script');
|
||||
var info = {};
|
||||
if (!(script instanceof Script)) {
|
||||
throw new TypeError('Address must be an instance of Script.');
|
||||
Address._transformScript = function(script, network) {
|
||||
$.checkArgument(script instanceof Script, 'script must be a Script instance');
|
||||
var info = script.getAddressInfo(network);
|
||||
if (!info) {
|
||||
throw new errors.Script.CantDeriveAddress(script);
|
||||
}
|
||||
if (script.isScriptHashOut()) {
|
||||
info.hashBuffer = script.getData();
|
||||
info.type = Address.PayToScriptHash;
|
||||
} else if (script.isPublicKeyHashOut()) {
|
||||
info.hashBuffer = script.getData();
|
||||
info.type = Address.PayToPublicKeyHash;
|
||||
} else {
|
||||
info.hashBuffer = Hash.sha256ripemd160(script.toBuffer());
|
||||
info.type = Address.PayToScriptHash;
|
||||
}
|
||||
info.network = Networks.get(network) || Networks.defaultNetwork;
|
||||
return info;
|
||||
};
|
||||
|
||||
|
@ -276,9 +265,8 @@ Address._transformScript = function(script, network){
|
|||
* @return {Address}
|
||||
*/
|
||||
Address.createMultisig = function(publicKeys, threshold, network) {
|
||||
var Script = require('./script');
|
||||
network = network || publicKeys[0].network;
|
||||
return new Address(Script.buildMultisigOut(publicKeys, threshold), network || Networks.defaultNetwork);
|
||||
network = network || publicKeys[0].network || Networks.defaultNetwork;
|
||||
return Address.payingTo(Script.buildMultisigOut(publicKeys, threshold), network);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -290,9 +278,9 @@ Address.createMultisig = function(publicKeys, threshold, network) {
|
|||
* @returns {Object} An object with keys: hashBuffer, network and type
|
||||
* @private
|
||||
*/
|
||||
Address._transformString = function(data, network, type){
|
||||
if( typeof(data) !== 'string' ) {
|
||||
throw new TypeError('Address supplied is not a string.');
|
||||
Address._transformString = function(data, network, type) {
|
||||
if (typeof(data) !== 'string') {
|
||||
throw new TypeError('data parameter supplied is not a string.');
|
||||
}
|
||||
var addressBuffer = Base58Check.decode(data);
|
||||
var info = Address._transformBuffer(addressBuffer, network, type);
|
||||
|
@ -306,7 +294,7 @@ Address._transformString = function(data, network, type){
|
|||
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
|
||||
* @returns {Address} A new valid and frozen instance of an Address
|
||||
*/
|
||||
Address.fromPublicKey = function(data, network){
|
||||
Address.fromPublicKey = function(data, network) {
|
||||
var info = Address._transformPublicKey(data);
|
||||
network = network || Networks.defaultNetwork;
|
||||
return new Address(info.hashBuffer, network, info.type);
|
||||
|
@ -332,18 +320,42 @@ Address.fromPublicKeyHash = function(hash, network) {
|
|||
* @returns {Address} A new valid and frozen instance of an Address
|
||||
*/
|
||||
Address.fromScriptHash = function(hash, network) {
|
||||
$.checkArgument(hash, 'hash parameter is required');
|
||||
var info = Address._transformHash(hash);
|
||||
return new Address(info.hashBuffer, network, Address.PayToScriptHash);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an address from a Script
|
||||
* Builds a p2sh address paying to script. This will hash the script and
|
||||
* use that to create the address.
|
||||
* If you want to extract an address associated with a script instead,
|
||||
* see {{Address#fromScript}}
|
||||
*
|
||||
* @param {Script} script - An instance of Script
|
||||
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
|
||||
* @returns {Address} A new valid and frozen instance of an Address
|
||||
*/
|
||||
Address.payingTo = function(script, network) {
|
||||
$.checkArgument(script, 'script is required');
|
||||
$.checkArgument(script instanceof Script, 'script must be instance of Script');
|
||||
|
||||
return Address.fromScriptHash(Hash.sha256ripemd160(script.toBuffer()), network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Extract address from a Script. The script must be of one
|
||||
* of the following types: p2pkh input, p2pkh output, p2sh input
|
||||
* or p2sh output.
|
||||
* This will analyze the script and extract address information from it.
|
||||
* If you want to transform any script to a p2sh Address paying
|
||||
* to that script's hash instead, use {{Address#payingTo}}
|
||||
*
|
||||
* @param {Script} script - An instance of Script
|
||||
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
|
||||
* @returns {Address} A new valid and frozen instance of an Address
|
||||
*/
|
||||
Address.fromScript = function(script, network) {
|
||||
$.checkArgument(script instanceof Script, 'script must be a Script instance');
|
||||
var info = Address._transformScript(script, network);
|
||||
return new Address(info.hashBuffer, network, info.type);
|
||||
};
|
||||
|
@ -494,7 +506,7 @@ Address.prototype.toString = function() {
|
|||
* @returns {string} Bitcoin address
|
||||
*/
|
||||
Address.prototype.inspect = function() {
|
||||
return '<Address: ' + this.toString() + ', type: '+this.type+', network: '+this.network+'>';
|
||||
return '<Address: ' + this.toString() + ', type: ' + this.type + ', network: ' + this.network + '>';
|
||||
};
|
||||
|
||||
module.exports = Address;
|
||||
|
|
|
@ -103,6 +103,12 @@ module.exports = [{
|
|||
errors: [{
|
||||
name: 'UnrecognizedAddress',
|
||||
message: 'Expected argument {0} to be an address'
|
||||
}, {
|
||||
name: 'CantDeriveAddress',
|
||||
message: 'Can\'t derive address associated with script {0}, needs to be p2pkh in, p2pkh out, p2sh in, or p2sh out.'
|
||||
}, {
|
||||
name: 'InvalidBuffer',
|
||||
message: 'Invalid script buffer: can\'t parse valid script from given buffer {0}'
|
||||
}]
|
||||
}, {
|
||||
name: 'HDPrivateKey',
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
var Address = require('./address');
|
||||
var BN = require('./crypto/bn');
|
||||
var Point = require('./crypto/point');
|
||||
var Hash = require('./crypto/hash');
|
||||
|
@ -404,6 +403,7 @@ PublicKey.prototype._getID = function _getID() {
|
|||
* @returns {Address} An address generated from the public key
|
||||
*/
|
||||
PublicKey.prototype.toAddress = function(network) {
|
||||
var Address = require('./address');
|
||||
return Address.fromPublicKey(this, network || this.network);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
var Address = require('../address');
|
||||
var BufferReader = require('../encoding/bufferreader');
|
||||
var BufferWriter = require('../encoding/bufferwriter');
|
||||
var Hash = require('../crypto/hash');
|
||||
|
@ -30,6 +29,7 @@ var Script = function Script(from) {
|
|||
if (!(this instanceof Script)) {
|
||||
return new Script(from);
|
||||
}
|
||||
var Address = require('../address');
|
||||
|
||||
this.chunks = [];
|
||||
|
||||
|
@ -57,44 +57,51 @@ Script.fromBuffer = function(buffer) {
|
|||
|
||||
var br = new BufferReader(buffer);
|
||||
while (!br.finished()) {
|
||||
var opcodenum = br.readUInt8();
|
||||
try {
|
||||
var opcodenum = br.readUInt8();
|
||||
|
||||
var len, buf;
|
||||
if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) {
|
||||
len = opcodenum;
|
||||
script.chunks.push({
|
||||
buf: br.read(len),
|
||||
len: len,
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
} else if (opcodenum === Opcode.OP_PUSHDATA1) {
|
||||
len = br.readUInt8();
|
||||
buf = br.read(len);
|
||||
script.chunks.push({
|
||||
buf: buf,
|
||||
len: len,
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
} else if (opcodenum === Opcode.OP_PUSHDATA2) {
|
||||
len = br.readUInt16LE();
|
||||
buf = br.read(len);
|
||||
script.chunks.push({
|
||||
buf: buf,
|
||||
len: len,
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
} else if (opcodenum === Opcode.OP_PUSHDATA4) {
|
||||
len = br.readUInt32LE();
|
||||
buf = br.read(len);
|
||||
script.chunks.push({
|
||||
buf: buf,
|
||||
len: len,
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
} else {
|
||||
script.chunks.push({
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
var len, buf;
|
||||
if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) {
|
||||
len = opcodenum;
|
||||
script.chunks.push({
|
||||
buf: br.read(len),
|
||||
len: len,
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
} else if (opcodenum === Opcode.OP_PUSHDATA1) {
|
||||
len = br.readUInt8();
|
||||
buf = br.read(len);
|
||||
script.chunks.push({
|
||||
buf: buf,
|
||||
len: len,
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
} else if (opcodenum === Opcode.OP_PUSHDATA2) {
|
||||
len = br.readUInt16LE();
|
||||
buf = br.read(len);
|
||||
script.chunks.push({
|
||||
buf: buf,
|
||||
len: len,
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
} else if (opcodenum === Opcode.OP_PUSHDATA4) {
|
||||
len = br.readUInt32LE();
|
||||
buf = br.read(len);
|
||||
script.chunks.push({
|
||||
buf: buf,
|
||||
len: len,
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
} else {
|
||||
script.chunks.push({
|
||||
opcodenum: opcodenum
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof RangeError) {
|
||||
throw new errors.Script.InvalidBuffer(buffer);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,15 +290,21 @@ Script.prototype.isScriptHashIn = function() {
|
|||
if (this.chunks.length === 0) {
|
||||
return false;
|
||||
}
|
||||
var chunk = this.chunks[this.chunks.length - 1];
|
||||
if (!chunk) {
|
||||
var redeemChunk = this.chunks[this.chunks.length - 1];
|
||||
var redeemBuf = redeemChunk.buf;
|
||||
if (!redeemBuf) {
|
||||
return false;
|
||||
}
|
||||
var scriptBuf = chunk.buf;
|
||||
if (!scriptBuf) {
|
||||
return false;
|
||||
|
||||
var redeemScript;
|
||||
try {
|
||||
redeemScript = Script.fromBuffer(redeemBuf);
|
||||
} catch (e) {
|
||||
if (e instanceof errors.Script.InvalidBuffer) {
|
||||
return false;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
var redeemScript = new Script(scriptBuf);
|
||||
var type = redeemScript.classify();
|
||||
return type !== Script.types.UNKNOWN;
|
||||
};
|
||||
|
@ -433,14 +446,12 @@ Script.prototype.equals = function(script) {
|
|||
}
|
||||
var i;
|
||||
for (i = 0; i < this.chunks.length; i++) {
|
||||
if (BufferUtil.isBuffer(this.chunks[i]) && !BufferUtil.isBuffer(script.chunks[i])) {
|
||||
return false;
|
||||
} else if (this.chunks[i] instanceof Opcode && !(script.chunks[i] instanceof Opcode)) {
|
||||
if (BufferUtil.isBuffer(this.chunks[i].buf) && !BufferUtil.isBuffer(script.chunks[i].buf)) {
|
||||
return false;
|
||||
}
|
||||
if (BufferUtil.isBuffer(this.chunks[i]) && !BufferUtil.equals(this.chunks[i], script.chunks[i])) {
|
||||
if (BufferUtil.isBuffer(this.chunks[i].buf) && !BufferUtil.equals(this.chunks[i].buf, script.chunks[i].buf)) {
|
||||
return false;
|
||||
} else if (this.chunks[i].num !== script.chunks[i].num) {
|
||||
} else if (this.chunks[i].opcodenum !== script.chunks[i].opcodenum) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -546,7 +557,7 @@ Script.prototype.removeCodeseparators = function() {
|
|||
*/
|
||||
Script.buildMultisigOut = function(publicKeys, threshold, opts) {
|
||||
$.checkArgument(threshold <= publicKeys.length,
|
||||
'Number of required signatures must be less than or equal to the number of public keys');
|
||||
'Number of required signatures must be less than or equal to the number of public keys');
|
||||
opts = opts || {};
|
||||
var script = new Script();
|
||||
script.add(Opcode.smallInt(threshold));
|
||||
|
@ -598,6 +609,7 @@ Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) {
|
|||
* @param {(Address|PublicKey)} to - destination address or public key
|
||||
*/
|
||||
Script.buildPublicKeyHashOut = function(to) {
|
||||
var Address = require('../address');
|
||||
$.checkArgument(!_.isUndefined(to));
|
||||
$.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to));
|
||||
if (to instanceof PublicKey) {
|
||||
|
@ -650,6 +662,7 @@ Script.buildDataOut = function(data) {
|
|||
* @returns {Script} new pay to script hash script for given script
|
||||
*/
|
||||
Script.buildScriptHashOut = function(script) {
|
||||
var Address = require('../address');
|
||||
$.checkArgument(script instanceof Script ||
|
||||
(script instanceof Address && script.isPayToScriptHash()));
|
||||
var s = new Script();
|
||||
|
@ -657,7 +670,7 @@ Script.buildScriptHashOut = function(script) {
|
|||
.add(script instanceof Address ? script.hashBuffer : Hash.sha256ripemd160(script.toBuffer()))
|
||||
.add(Opcode.OP_EQUAL);
|
||||
|
||||
s._network = script._network || script.network;
|
||||
s._network = script._network || script.network;
|
||||
return s;
|
||||
};
|
||||
|
||||
|
@ -699,9 +712,10 @@ Script.prototype.toScriptHashOut = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
* @return {Script} a script built from the address
|
||||
* @return {Script} an output script built from the address
|
||||
*/
|
||||
Script.fromAddress = function(address) {
|
||||
var Address = require('../address');
|
||||
address = Address(address);
|
||||
if (address.isPayToScriptHash()) {
|
||||
return Script.buildScriptHashOut(address);
|
||||
|
@ -713,14 +727,44 @@ Script.fromAddress = function(address) {
|
|||
|
||||
/**
|
||||
* @param {Network=} network
|
||||
* @return {Address} the associated address for this script
|
||||
* @return {Address|boolean} the associated address information object
|
||||
* for this script if any, or false
|
||||
*/
|
||||
Script.prototype.getAddressInfo = function() {
|
||||
var Address = require('../address');
|
||||
var info = {};
|
||||
if (this.isScriptHashOut()) {
|
||||
info.hashBuffer = this.getData();
|
||||
info.type = Address.PayToScriptHash;
|
||||
} else if (this.isPublicKeyHashOut()) {
|
||||
info.hashBuffer = this.getData();
|
||||
info.type = Address.PayToPublicKeyHash;
|
||||
} else if (this.isPublicKeyHashIn()) {
|
||||
// hash the publickey found in the scriptSig
|
||||
info.hashBuffer = Hash.sha256ripemd160(this.chunks[1].buf);
|
||||
info.type = Address.PayToPublicKeyHash;
|
||||
} else if (this.isScriptHashIn()) {
|
||||
// hash the redeemscript found at the end of the scriptSig
|
||||
info.hashBuffer = Hash.sha256ripemd160(this.chunks[this.chunks.length - 1].buf);
|
||||
info.type = Address.PayToScriptHash;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return info;
|
||||
};
|
||||
/**
|
||||
* @param {Network=} network
|
||||
* @return {Address|boolean} the associated address for this script if possible, or false
|
||||
*/
|
||||
Script.prototype.toAddress = function(network) {
|
||||
var Address = require('../address');
|
||||
network = Networks.get(network) || this._network || Networks.defaultNetwork;
|
||||
if (this.isPublicKeyHashOut() || this.isScriptHashOut()) {
|
||||
return new Address(this, network);
|
||||
var info = this.getAddressInfo();
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
throw new Error('The script type needs to be PayToPublicKeyHash or PayToScriptHash');
|
||||
info.network = Networks.get(network) || Networks.defaultNetwork;
|
||||
return new Address(info);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,7 +28,7 @@ describe('Address', function() {
|
|||
});
|
||||
|
||||
it('should throw an error because of bad network param', function() {
|
||||
(function(){
|
||||
(function() {
|
||||
return new Address(PKHLivenet[0], 'main', 'pubkeyhash');
|
||||
}).should.throw('Second argument must be "livenet" or "testnet".');
|
||||
});
|
||||
|
@ -40,7 +40,7 @@ describe('Address', function() {
|
|||
});
|
||||
|
||||
describe('bitcoind compliance', function() {
|
||||
validbase58.map(function(d){
|
||||
validbase58.map(function(d) {
|
||||
if (!d[2].isPrivkey) {
|
||||
it('should describe address ' + d[0] + ' as valid', function() {
|
||||
var type;
|
||||
|
@ -57,8 +57,8 @@ describe('Address', function() {
|
|||
});
|
||||
}
|
||||
});
|
||||
invalidbase58.map(function(d){
|
||||
it('should describe input ' + d[0].slice(0,10) + '... as invalid', function() {
|
||||
invalidbase58.map(function(d) {
|
||||
it('should describe input ' + d[0].slice(0, 10) + '... as invalid', function() {
|
||||
expect(function() {
|
||||
return new Address(d[0]);
|
||||
}).to.throw(Error);
|
||||
|
@ -121,12 +121,12 @@ describe('Address', function() {
|
|||
should.exist(error);
|
||||
});
|
||||
|
||||
it('isValid returns true on a valid address', function(){
|
||||
it('isValid returns true on a valid address', function() {
|
||||
var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'livenet');
|
||||
valid.should.equal(true);
|
||||
});
|
||||
|
||||
it('isValid returns false on network mismatch', function(){
|
||||
it('isValid returns false on network mismatch', function() {
|
||||
var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'testnet');
|
||||
valid.should.equal(false);
|
||||
});
|
||||
|
@ -280,13 +280,13 @@ describe('Address', function() {
|
|||
it('should error because of incorrect type for script transform', function() {
|
||||
(function() {
|
||||
return Address._transformScript(new Buffer(20));
|
||||
}).should.throw('Address must be an instance of Script.');
|
||||
}).should.throw('Invalid Argument: script must be a Script instance');
|
||||
});
|
||||
|
||||
it('should error because of incorrect type for string transform', function() {
|
||||
(function() {
|
||||
return Address._transformString(new Buffer(20));
|
||||
}).should.throw('Address supplied is not a string.');
|
||||
}).should.throw('data parameter supplied is not a string.');
|
||||
});
|
||||
|
||||
it('should make an address from a pubkey hash buffer', function() {
|
||||
|
@ -328,7 +328,7 @@ describe('Address', function() {
|
|||
|
||||
it('should make this address from an uncompressed pubkey', function() {
|
||||
var pubkey = new PublicKey('0485e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b00' +
|
||||
'4833fef26c8be4c4823754869ff4e46755b85d851077771c220e2610496a29d98');
|
||||
'4833fef26c8be4c4823754869ff4e46755b85d851077771c220e2610496a29d98');
|
||||
var a = Address.fromPublicKey(pubkey, 'livenet');
|
||||
a.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX');
|
||||
var b = new Address(pubkey, 'livenet', 'pubkeyhash');
|
||||
|
@ -336,23 +336,28 @@ describe('Address', function() {
|
|||
});
|
||||
|
||||
describe('from a script', function() {
|
||||
it('should make this address from a script', function() {
|
||||
var s = Script.fromString('OP_CHECKMULTISIG');
|
||||
it('should fail to build address from a non p2sh,p2pkh script', function() {
|
||||
var s = new Script('OP_CHECKMULTISIG');
|
||||
(function() {
|
||||
return new Address(s);
|
||||
}).should.throw('needs to be p2pkh in, p2pkh out, p2sh in, or p2sh out');
|
||||
});
|
||||
it('should make this address from a p2pkh output script', function() {
|
||||
var s = new Script('OP_DUP OP_HASH160 20 ' +
|
||||
'0xc8e11b0eb0d2ad5362d894f048908341fa61b6e1 OP_EQUALVERIFY OP_CHECKSIG');
|
||||
var buf = s.toBuffer();
|
||||
var a = Address.fromScript(s, 'livenet');
|
||||
a.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm');
|
||||
a.toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
|
||||
var b = new Address(s, 'livenet');
|
||||
b.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm');
|
||||
var c = Address.fromScriptHash(bitcore.crypto.Hash.sha256ripemd160(buf), 'livenet');
|
||||
c.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm');
|
||||
b.toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
|
||||
});
|
||||
|
||||
it('should make this address from other script', function() {
|
||||
var s = Script.fromString('OP_CHECKSIG OP_HASH160');
|
||||
it('should make this address from a p2sh input script', function() {
|
||||
var s = Script.fromString('OP_HASH160 20 0xa6ed4af315271e657ee307828f54a4365fa5d20f OP_EQUAL');
|
||||
var a = Address.fromScript(s, 'livenet');
|
||||
a.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7');
|
||||
a.toString().should.equal('3GueMn6ruWVfQTN4XKBGEbCbGLwRSUhfnS');
|
||||
var b = new Address(s, 'livenet');
|
||||
b.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7');
|
||||
b.toString().should.equal('3GueMn6ruWVfQTN4XKBGEbCbGLwRSUhfnS');
|
||||
});
|
||||
|
||||
it('returns the same address if the script is a pay to public key hash out', function() {
|
||||
|
@ -487,6 +492,8 @@ describe('Address', function() {
|
|||
it('can create an address from a set of public keys', function() {
|
||||
var address = Address.createMultisig(publics, 2, Networks.livenet);
|
||||
address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y');
|
||||
address = new Address(publics, 2, Networks.livenet);
|
||||
address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y');
|
||||
});
|
||||
|
||||
it('works on testnet also', function() {
|
||||
|
@ -502,7 +509,7 @@ describe('Address', function() {
|
|||
|
||||
it('fails if invalid array is provided', function() {
|
||||
expect(function() {
|
||||
return Address.createMultisig([],3,'testnet');
|
||||
return Address.createMultisig([], 3, 'testnet');
|
||||
}).to.throw('Number of required signatures must be less than or equal to the number of public keys');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,6 +11,8 @@ var Opcode = bitcore.Opcode;
|
|||
var PublicKey = bitcore.PublicKey;
|
||||
var Address = bitcore.Address;
|
||||
|
||||
var script_valid = require('../data/bitcoind/script_valid');
|
||||
|
||||
describe('Script', function() {
|
||||
|
||||
it('should make a new script', function() {
|
||||
|
@ -308,6 +310,16 @@ describe('Script', function() {
|
|||
it('should identify this known non-scripthashin', function() {
|
||||
Script('20 0000000000000000000000000000000000000000 OP_CHECKSIG').isScriptHashIn().should.equal(false);
|
||||
});
|
||||
|
||||
it('should identify this problematic non-scripthashin scripts', function() {
|
||||
var s = new Script('71 0x3044022017053dad84aa06213749df50a03330cfd24d6' +
|
||||
'b8e7ddbb6de66c03697b78a752a022053bc0faca8b4049fb3944a05fcf7c93b2861' +
|
||||
'734d39a89b73108f605f70f5ed3401 33 0x0225386e988b84248dc9c30f784b06e' +
|
||||
'02fdec57bbdbd443768eb5744a75ce44a4c');
|
||||
var s2 = new Script('OP_RETURN 32 0x19fdb20634911b6459e6086658b3a6ad2dc6576bd6826c73ee86a5f9aec14ed9');
|
||||
s.isScriptHashIn().should.equal(false);
|
||||
s2.isScriptHashIn().should.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isScripthashOut', function() {
|
||||
|
@ -641,18 +653,17 @@ describe('Script', function() {
|
|||
it('priorize the network argument', function() {
|
||||
var script = new Script(liveAddress);
|
||||
script.toAddress(Networks.testnet).toString().should.equal(testAddress.toString());
|
||||
|
||||
var s = new Script('OP_DUP OP_HASH160 20 0x06c06f6d931d7bfba2b5bd5ad0d19a8f257af3e3 OP_EQUALVERIFY OP_CHECKSIG');
|
||||
script.toAddress(Networks.testnet).network.should.equal(Networks.testnet);
|
||||
});
|
||||
it('use the inherited network', function() {
|
||||
var script = new Script(liveAddress);
|
||||
script.toAddress().toString().should.equal(liveAddress.toString());
|
||||
var script = new Script(testAddress);
|
||||
script = new Script(testAddress);
|
||||
script.toAddress().toString().should.equal(testAddress.toString());
|
||||
});
|
||||
it('uses default network', function() {
|
||||
var script = new Script('OP_DUP OP_HASH160 20 0x06c06f6d931d7bfba2b5bd5ad0d19a8f257af3e3 OP_EQUALVERIFY OP_CHECKSIG');
|
||||
var script = new Script('OP_DUP OP_HASH160 20 ' +
|
||||
'0x06c06f6d931d7bfba2b5bd5ad0d19a8f257af3e3 OP_EQUALVERIFY OP_CHECKSIG');
|
||||
script.toAddress().network.should.equal(Networks.defaultNetwork);
|
||||
});
|
||||
it('for a P2PKH address', function() {
|
||||
|
@ -668,9 +679,57 @@ describe('Script', function() {
|
|||
script.toAddress().toString().should.equal(stringAddress);
|
||||
});
|
||||
it('fails if content is not recognized', function() {
|
||||
expect(function() {
|
||||
return Script().toAddress(Networks.livenet);
|
||||
}).to.throw();
|
||||
Script().toAddress(Networks.livenet).should.equal(false);
|
||||
});
|
||||
|
||||
it('works for p2pkh output', function() {
|
||||
// taken from tx 7e519caca256423320b92e3e17be5701f87afecbdb3f53af598032bfd8d164f5
|
||||
var script = new Script('OP_DUP OP_HASH160 20 ' +
|
||||
'0xc8e11b0eb0d2ad5362d894f048908341fa61b6e1 OP_EQUALVERIFY OP_CHECKSIG');
|
||||
script.toAddress().toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
|
||||
});
|
||||
it('works for p2pkh input', function() {
|
||||
// taken from tx 7e519caca256423320b92e3e17be5701f87afecbdb3f53af598032bfd8d164f5
|
||||
var script = new Script('72 0x3045022100eff96230ca0f55b1e8c7a63e014f48611ff1af40875ecd33dee9062d7a6f5e2002206320405b5f6992c756e03e66b21a05a812b60996464ac6af815c2638b930dd7a01 65 0x04150defa035a2c7d826d7d5fc8ab2154bd1bb832f1a5c8ecb338f436362ad232e428b57db44677c5a8bd42c5ed9e2d7e04e742c59bee1b40080cfd57dec64b23a');
|
||||
script.toAddress().toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
|
||||
// taken from tx 7f8f95752a59d715dae9e0008a42e7968d2736741591bbfc6685f6e1649c21ed
|
||||
var s2 = new Script('71 0x3044022017053dad84aa06213749df50a03330cfd24d6b8e7ddbb6de66c03697b78a752a022053bc0faca8b4049fb3944a05fcf7c93b2861734d39a89b73108f605f70f5ed3401 33 0x0225386e988b84248dc9c30f784b06e02fdec57bbdbd443768eb5744a75ce44a4c');
|
||||
s2.toAddress().toString().should.equal('17VArX6GRE6i6MVscBUZoXwi6NhnHa68B7');
|
||||
});
|
||||
|
||||
it('works for p2sh output', function() {
|
||||
// taken from tx fe1f764299dc7f3b5a8fae912050df2b633bf99554c68bf1c456edb9c2b63585
|
||||
var script = new Script('OP_HASH160 20 0x99d29051af0c29adcb9040034752bba7dde33e35 OP_EQUAL');
|
||||
script.toAddress().toString().should.equal('3FiMZ7stbfH2WG5JQ7CiuzrFo7CEnGUcAP');
|
||||
});
|
||||
it('works for p2sh input', function() {
|
||||
// taken from tx fe1f764299dc7f3b5a8fae912050df2b633bf99554c68bf1c456edb9c2b63585
|
||||
var script = new Script('OP_FALSE 72 0x3045022100e824fbe979fac5834d0062dd5a4e82a898e00ac454bd254cd708ad28530816f202206251ff0fa4dd70c0524c690d4e4deb2bd167297e7bbdf6743b4a8050d681555001 37 0x512102ff3ae0aaa4679ea156d5581dbe6695cc0c311df0aa42af76670d0debbd8f672951ae');
|
||||
script.toAddress().toString().should.equal('3GYicPxCvsKvbJmZNBBeWkC3cLuGFhtrQi');
|
||||
});
|
||||
|
||||
// no address scripts
|
||||
it('works for OP_RETURN script', function() {
|
||||
var script = new Script('OP_RETURN 20 0x99d29051af0c29adcb9040034752bba7dde33e35');
|
||||
script.toAddress().should.equal(false);
|
||||
});
|
||||
|
||||
});
|
||||
describe('equals', function() {
|
||||
it('returns true for same script', function() {
|
||||
Script('OP_TRUE').equals(Script('OP_TRUE')).should.equal(true);
|
||||
});
|
||||
it('returns false for different chunks sizes', function() {
|
||||
Script('OP_TRUE').equals(Script('OP_TRUE OP_TRUE')).should.equal(false);
|
||||
});
|
||||
it('returns false for different opcodes', function() {
|
||||
Script('OP_TRUE OP_TRUE').equals(Script('OP_TRUE OP_FALSE')).should.equal(false);
|
||||
});
|
||||
it('returns false for different data', function() {
|
||||
Script().add(new Buffer('a')).equals(Script('OP_TRUE')).should.equal(false);
|
||||
});
|
||||
it('returns false for different data', function() {
|
||||
Script().add(new Buffer('a')).equals(Script().add(new Buffer('b'))).should.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue