refactor Address<->Script relation

This commit is contained in:
Manuel Araoz 2015-03-18 16:54:16 -03:00
parent f2ef86f31a
commit 62ea45a524
6 changed files with 131 additions and 60 deletions

View File

@ -2,10 +2,13 @@
var _ = require('lodash'); var _ = require('lodash');
var $ = require('./util/preconditions'); var $ = require('./util/preconditions');
var errors = require('./errors');
var Base58Check = require('./encoding/base58check'); var Base58Check = require('./encoding/base58check');
var Networks = require('./networks'); var Networks = require('./networks');
var Hash = require('./crypto/hash'); var Hash = require('./crypto/hash');
var JSUtil = require('./util/js'); 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, * 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" * @returns {Object} An "info" object with "type", "network", and "hashBuffer"
*/ */
Address.prototype._classifyArguments = function(data, network, type) { Address.prototype._classifyArguments = function(data, network, type) {
var PublicKey = require('./publickey');
var Script = require('./script');
/* jshint maxcomplexity: 10 */ /* jshint maxcomplexity: 10 */
// transform and validate input data // transform and validate input data
if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 20) { if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 20) {
@ -122,7 +123,7 @@ Address.PayToScriptHash = 'scripthash';
* @returns {Object} An object with keys: hashBuffer * @returns {Object} An object with keys: hashBuffer
* @private * @private
*/ */
Address._transformHash = function(hash){ Address._transformHash = function(hash) {
var info = {}; var info = {};
if (!(hash instanceof Buffer) && !(hash instanceof Uint8Array)) { if (!(hash instanceof Buffer) && !(hash instanceof Uint8Array)) {
throw new TypeError('Address supplied is not a buffer.'); 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 * @returns {Object} An object with keys: network and type
* @private * @private
*/ */
Address._classifyFromVersion = function(buffer){ Address._classifyFromVersion = function(buffer) {
var version = {}; var version = {};
version.network = Networks.get(buffer[0]); version.network = Networks.get(buffer[0]);
switch (buffer[0]) { // the version byte switch (buffer[0]) { // the version byte
@ -191,7 +192,7 @@ Address._classifyFromVersion = function(buffer){
* @returns {Object} An object with keys: hashBuffer, network and type * @returns {Object} An object with keys: hashBuffer, network and type
* @private * @private
*/ */
Address._transformBuffer = function(buffer, network, type){ Address._transformBuffer = function(buffer, network, type) {
/* jshint maxcomplexity: 9 */ /* jshint maxcomplexity: 9 */
var info = {}; var info = {};
if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) { 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.'); 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.'); 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 * @returns {Object} An object with keys: hashBuffer, type
* @private * @private
*/ */
Address._transformPublicKey = function(pubkey){ Address._transformPublicKey = function(pubkey) {
var PublicKey = require('./publickey');
var info = {}; var info = {};
if (!(pubkey instanceof PublicKey)) { if (!(pubkey instanceof PublicKey)) {
throw new TypeError('Address must be an instance of PublicKey.'); throw new TypeError('Address must be an instance of PublicKey.');
@ -243,11 +243,10 @@ Address._transformPublicKey = function(pubkey){
* @returns {Object} An object with keys: hashBuffer, type * @returns {Object} An object with keys: hashBuffer, type
* @private * @private
*/ */
Address._transformScript = function(script, network){ Address._transformScript = function(script, network) {
var Script = require('./script');
var info = {}; var info = {};
if (!(script instanceof Script)) { if (!(script instanceof Script)) {
throw new TypeError('Address must be an instance of Script.'); throw new TypeError('script must be an instance of Script.');
} }
if (script.isScriptHashOut()) { if (script.isScriptHashOut()) {
info.hashBuffer = script.getData(); info.hashBuffer = script.getData();
@ -255,9 +254,16 @@ Address._transformScript = function(script, network){
} else if (script.isPublicKeyHashOut()) { } else if (script.isPublicKeyHashOut()) {
info.hashBuffer = script.getData(); info.hashBuffer = script.getData();
info.type = Address.PayToPublicKeyHash; info.type = Address.PayToPublicKeyHash;
} else { } else if (script.isScriptHashIn()) {
info.hashBuffer = Hash.sha256ripemd160(script.toBuffer()); // hash the redeemscript found at the end of the scriptSig
info.hashBuffer = Hash.sha256ripemd160(script.chunks[script.chunks.length - 1].buf);
info.type = Address.PayToScriptHash; info.type = Address.PayToScriptHash;
} else if (script.isPublicKeyHashIn()) {
// hash the publickey found in the scriptSig
info.hashBuffer = Hash.sha256ripemd160(script.chunks[1].buf);
info.type = Address.PayToPublicKeyHash;
} else {
throw new errors.Script.CantDeriveAddress(script);
} }
info.network = Networks.get(network) || Networks.defaultNetwork; info.network = Networks.get(network) || Networks.defaultNetwork;
return info; return info;
@ -276,9 +282,8 @@ Address._transformScript = function(script, network){
* @return {Address} * @return {Address}
*/ */
Address.createMultisig = function(publicKeys, threshold, network) { Address.createMultisig = function(publicKeys, threshold, network) {
var Script = require('./script'); network = network || publicKeys[0].network || Networks.defaultNetwork;
network = network || publicKeys[0].network; return Address.payingTo(Script.buildMultisigOut(publicKeys, threshold), network);
return new Address(Script.buildMultisigOut(publicKeys, threshold), network || Networks.defaultNetwork);
}; };
/** /**
@ -290,8 +295,8 @@ Address.createMultisig = function(publicKeys, threshold, network) {
* @returns {Object} An object with keys: hashBuffer, network and type * @returns {Object} An object with keys: hashBuffer, network and type
* @private * @private
*/ */
Address._transformString = function(data, network, type){ Address._transformString = function(data, network, type) {
if( typeof(data) !== 'string' ) { if (typeof(data) !== 'string') {
throw new TypeError('Address supplied is not a string.'); throw new TypeError('Address supplied is not a string.');
} }
var addressBuffer = Base58Check.decode(data); var addressBuffer = Base58Check.decode(data);
@ -306,7 +311,7 @@ Address._transformString = function(data, network, type){
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address * @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); var info = Address._transformPublicKey(data);
network = network || Networks.defaultNetwork; network = network || Networks.defaultNetwork;
return new Address(info.hashBuffer, network, info.type); return new Address(info.hashBuffer, network, info.type);
@ -332,12 +337,35 @@ Address.fromPublicKeyHash = function(hash, network) {
* @returns {Address} A new valid and frozen instance of an Address * @returns {Address} A new valid and frozen instance of an Address
*/ */
Address.fromScriptHash = function(hash, network) { Address.fromScriptHash = function(hash, network) {
$.checkArgument(hash, 'hash parameter is required');
var info = Address._transformHash(hash); var info = Address._transformHash(hash);
return new Address(info.hashBuffer, network, Address.PayToScriptHash); 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 {Script} script - An instance of Script
* @param {String|Network} network - either a Network instance, 'livenet', or 'testnet' * @param {String|Network} network - either a Network instance, 'livenet', or 'testnet'
@ -494,7 +522,7 @@ Address.prototype.toString = function() {
* @returns {string} Bitcoin address * @returns {string} Bitcoin address
*/ */
Address.prototype.inspect = function() { 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; module.exports = Address;

View File

@ -103,6 +103,9 @@ module.exports = [{
errors: [{ errors: [{
name: 'UnrecognizedAddress', name: 'UnrecognizedAddress',
message: 'Expected argument {0} to be an address' 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: 'HDPrivateKey', name: 'HDPrivateKey',

View File

@ -1,6 +1,5 @@
'use strict'; 'use strict';
var Address = require('./address');
var BN = require('./crypto/bn'); var BN = require('./crypto/bn');
var Point = require('./crypto/point'); var Point = require('./crypto/point');
var Hash = require('./crypto/hash'); var Hash = require('./crypto/hash');
@ -404,6 +403,7 @@ PublicKey.prototype._getID = function _getID() {
* @returns {Address} An address generated from the public key * @returns {Address} An address generated from the public key
*/ */
PublicKey.prototype.toAddress = function(network) { PublicKey.prototype.toAddress = function(network) {
var Address = require('./address');
return Address.fromPublicKey(this, network || this.network); return Address.fromPublicKey(this, network || this.network);
}; };

View File

@ -1,7 +1,6 @@
'use strict'; 'use strict';
var Address = require('../address');
var BufferReader = require('../encoding/bufferreader'); var BufferReader = require('../encoding/bufferreader');
var BufferWriter = require('../encoding/bufferwriter'); var BufferWriter = require('../encoding/bufferwriter');
var Hash = require('../crypto/hash'); var Hash = require('../crypto/hash');
@ -30,6 +29,7 @@ var Script = function Script(from) {
if (!(this instanceof Script)) { if (!(this instanceof Script)) {
return new Script(from); return new Script(from);
} }
var Address = require('../address');
this.chunks = []; this.chunks = [];
@ -283,15 +283,15 @@ Script.prototype.isScriptHashIn = function() {
if (this.chunks.length === 0) { if (this.chunks.length === 0) {
return false; return false;
} }
var chunk = this.chunks[this.chunks.length - 1]; var redeemChunk = this.chunks[this.chunks.length - 1];
if (!chunk) { if (!redeemChunk) {
return false; return false;
} }
var scriptBuf = chunk.buf; var redeemBuf = redeemChunk.buf;
if (!scriptBuf) { if (!redeemBuf) {
return false; return false;
} }
var redeemScript = new Script(scriptBuf); var redeemScript = new Script(redeemBuf);
var type = redeemScript.classify(); var type = redeemScript.classify();
return type !== Script.types.UNKNOWN; return type !== Script.types.UNKNOWN;
}; };
@ -546,7 +546,7 @@ Script.prototype.removeCodeseparators = function() {
*/ */
Script.buildMultisigOut = function(publicKeys, threshold, opts) { Script.buildMultisigOut = function(publicKeys, threshold, opts) {
$.checkArgument(threshold <= publicKeys.length, $.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 || {}; opts = opts || {};
var script = new Script(); var script = new Script();
script.add(Opcode.smallInt(threshold)); script.add(Opcode.smallInt(threshold));
@ -598,6 +598,7 @@ Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) {
* @param {(Address|PublicKey)} to - destination address or public key * @param {(Address|PublicKey)} to - destination address or public key
*/ */
Script.buildPublicKeyHashOut = function(to) { Script.buildPublicKeyHashOut = function(to) {
var Address = require('../address');
$.checkArgument(!_.isUndefined(to)); $.checkArgument(!_.isUndefined(to));
$.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to)); $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to));
if (to instanceof PublicKey) { if (to instanceof PublicKey) {
@ -650,6 +651,7 @@ Script.buildDataOut = function(data) {
* @returns {Script} new pay to script hash script for given script * @returns {Script} new pay to script hash script for given script
*/ */
Script.buildScriptHashOut = function(script) { Script.buildScriptHashOut = function(script) {
var Address = require('../address');
$.checkArgument(script instanceof Script || $.checkArgument(script instanceof Script ||
(script instanceof Address && script.isPayToScriptHash())); (script instanceof Address && script.isPayToScriptHash()));
var s = new Script(); var s = new Script();
@ -657,7 +659,7 @@ Script.buildScriptHashOut = function(script) {
.add(script instanceof Address ? script.hashBuffer : Hash.sha256ripemd160(script.toBuffer())) .add(script instanceof Address ? script.hashBuffer : Hash.sha256ripemd160(script.toBuffer()))
.add(Opcode.OP_EQUAL); .add(Opcode.OP_EQUAL);
s._network = script._network || script.network; s._network = script._network || script.network;
return s; return s;
}; };
@ -699,9 +701,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) { Script.fromAddress = function(address) {
var Address = require('../address');
address = Address(address); address = Address(address);
if (address.isPayToScriptHash()) { if (address.isPayToScriptHash()) {
return Script.buildScriptHashOut(address); return Script.buildScriptHashOut(address);
@ -713,14 +716,19 @@ Script.fromAddress = function(address) {
/** /**
* @param {Network=} network * @param {Network=} network
* @return {Address} the associated address for this script * @return {Address|boolean} the associated address for this script if possible, or false
*/ */
Script.prototype.toAddress = function(network) { Script.prototype.toAddress = function(network) {
var Address = require('../address');
network = Networks.get(network) || this._network || Networks.defaultNetwork; network = Networks.get(network) || this._network || Networks.defaultNetwork;
if (this.isPublicKeyHashOut() || this.isScriptHashOut()) { var canConvertToAddress = this.isPublicKeyHashOut() ||
this.isScriptHashOut() ||
this.isPublicKeyHashIn() ||
this.isScriptHashIn();
if (canConvertToAddress) {
return new Address(this, network); return new Address(this, network);
} }
throw new Error('The script type needs to be PayToPublicKeyHash or PayToScriptHash'); return false;
}; };
/** /**

View File

@ -28,7 +28,7 @@ describe('Address', function() {
}); });
it('should throw an error because of bad network param', function() { it('should throw an error because of bad network param', function() {
(function(){ (function() {
return new Address(PKHLivenet[0], 'main', 'pubkeyhash'); return new Address(PKHLivenet[0], 'main', 'pubkeyhash');
}).should.throw('Second argument must be "livenet" or "testnet".'); }).should.throw('Second argument must be "livenet" or "testnet".');
}); });
@ -40,7 +40,7 @@ describe('Address', function() {
}); });
describe('bitcoind compliance', function() { describe('bitcoind compliance', function() {
validbase58.map(function(d){ validbase58.map(function(d) {
if (!d[2].isPrivkey) { if (!d[2].isPrivkey) {
it('should describe address ' + d[0] + ' as valid', function() { it('should describe address ' + d[0] + ' as valid', function() {
var type; var type;
@ -57,8 +57,8 @@ describe('Address', function() {
}); });
} }
}); });
invalidbase58.map(function(d){ invalidbase58.map(function(d) {
it('should describe input ' + d[0].slice(0,10) + '... as invalid', function() { it('should describe input ' + d[0].slice(0, 10) + '... as invalid', function() {
expect(function() { expect(function() {
return new Address(d[0]); return new Address(d[0]);
}).to.throw(Error); }).to.throw(Error);
@ -121,12 +121,12 @@ describe('Address', function() {
should.exist(error); 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'); var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'livenet');
valid.should.equal(true); 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'); var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'testnet');
valid.should.equal(false); valid.should.equal(false);
}); });
@ -280,7 +280,7 @@ describe('Address', function() {
it('should error because of incorrect type for script transform', function() { it('should error because of incorrect type for script transform', function() {
(function() { (function() {
return Address._transformScript(new Buffer(20)); return Address._transformScript(new Buffer(20));
}).should.throw('Address must be an instance of Script.'); }).should.throw('script must be an instance of Script.');
}); });
it('should error because of incorrect type for string transform', function() { it('should error because of incorrect type for string transform', function() {
@ -328,7 +328,7 @@ describe('Address', function() {
it('should make this address from an uncompressed pubkey', function() { it('should make this address from an uncompressed pubkey', function() {
var pubkey = new PublicKey('0485e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b00' + var pubkey = new PublicKey('0485e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b00' +
'4833fef26c8be4c4823754869ff4e46755b85d851077771c220e2610496a29d98'); '4833fef26c8be4c4823754869ff4e46755b85d851077771c220e2610496a29d98');
var a = Address.fromPublicKey(pubkey, 'livenet'); var a = Address.fromPublicKey(pubkey, 'livenet');
a.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX'); a.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX');
var b = new Address(pubkey, 'livenet', 'pubkeyhash'); var b = new Address(pubkey, 'livenet', 'pubkeyhash');
@ -336,23 +336,28 @@ describe('Address', function() {
}); });
describe('from a script', function() { describe('from a script', function() {
it('should make this address from a script', function() { it('should fail to build address from a non p2sh,p2pkh script', function() {
var s = Script.fromString('OP_CHECKMULTISIG'); 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 buf = s.toBuffer();
var a = Address.fromScript(s, 'livenet'); var a = Address.fromScript(s, 'livenet');
a.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); a.toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
var b = new Address(s, 'livenet'); var b = new Address(s, 'livenet');
b.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); b.toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
var c = Address.fromScriptHash(bitcore.crypto.Hash.sha256ripemd160(buf), 'livenet');
c.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm');
}); });
it('should make this address from other script', function() { it('should make this address from a p2sh input script', function() {
var s = Script.fromString('OP_CHECKSIG OP_HASH160'); var s = Script.fromString('OP_HASH160 20 0xa6ed4af315271e657ee307828f54a4365fa5d20f OP_EQUAL');
var a = Address.fromScript(s, 'livenet'); var a = Address.fromScript(s, 'livenet');
a.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7'); a.toString().should.equal('3GueMn6ruWVfQTN4XKBGEbCbGLwRSUhfnS');
var b = new Address(s, 'livenet'); 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() { 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() { it('can create an address from a set of public keys', function() {
var address = Address.createMultisig(publics, 2, Networks.livenet); var address = Address.createMultisig(publics, 2, Networks.livenet);
address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y'); address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y');
address = new Address(publics, 2, Networks.livenet);
address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y');
}); });
it('works on testnet also', function() { it('works on testnet also', function() {
@ -502,7 +509,7 @@ describe('Address', function() {
it('fails if invalid array is provided', function() { it('fails if invalid array is provided', function() {
expect(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'); }).to.throw('Number of required signatures must be less than or equal to the number of public keys');
}); });
}); });

View File

@ -641,18 +641,17 @@ describe('Script', function() {
it('priorize the network argument', function() { it('priorize the network argument', function() {
var script = new Script(liveAddress); var script = new Script(liveAddress);
script.toAddress(Networks.testnet).toString().should.equal(testAddress.toString()); 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); script.toAddress(Networks.testnet).network.should.equal(Networks.testnet);
}); });
it('use the inherited network', function() { it('use the inherited network', function() {
var script = new Script(liveAddress); var script = new Script(liveAddress);
script.toAddress().toString().should.equal(liveAddress.toString()); script.toAddress().toString().should.equal(liveAddress.toString());
var script = new Script(testAddress); script = new Script(testAddress);
script.toAddress().toString().should.equal(testAddress.toString()); script.toAddress().toString().should.equal(testAddress.toString());
}); });
it('uses default network', function() { 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); script.toAddress().network.should.equal(Networks.defaultNetwork);
}); });
it('for a P2PKH address', function() { it('for a P2PKH address', function() {
@ -668,10 +667,36 @@ describe('Script', function() {
script.toAddress().toString().should.equal(stringAddress); script.toAddress().toString().should.equal(stringAddress);
}); });
it('fails if content is not recognized', function() { it('fails if content is not recognized', function() {
expect(function() { Script().toAddress(Networks.livenet).should.equal(false);
return Script().toAddress(Networks.livenet);
}).to.throw();
}); });
// taken from txid 7e519caca256423320b92e3e17be5701f87afecbdb3f53af598032bfd8d164f5
it('works for p2pkh output', function() {
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() {
var script = new Script('72 0x3045022100eff96230ca0f55b1e8c7a63e014f48611ff1af40875ecd33dee9062d7a6f5e2002206320405b5f6992c756e03e66b21a05a812b60996464ac6af815c2638b930dd7a01 65 0x04150defa035a2c7d826d7d5fc8ab2154bd1bb832f1a5c8ecb338f436362ad232e428b57db44677c5a8bd42c5ed9e2d7e04e742c59bee1b40080cfd57dec64b23a');
script.toAddress().toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
});
// taken from txid fe1f764299dc7f3b5a8fae912050df2b633bf99554c68bf1c456edb9c2b63585
it('works for p2sh output', function() {
var script = new Script('OP_HASH160 20 0x99d29051af0c29adcb9040034752bba7dde33e35 OP_EQUAL');
script.toAddress().toString().should.equal('3FiMZ7stbfH2WG5JQ7CiuzrFo7CEnGUcAP');
});
it('works for p2sh input', function() {
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);
});
}); });
}); });