Merge pull request #864 from eordano/feature/getAddress

Add toAddress(network) functionality to scripts
This commit is contained in:
Yemel Jardi 2014-12-30 16:31:37 -03:00
commit 6d1c5d39a3
4 changed files with 94 additions and 39 deletions

View File

@ -234,9 +234,17 @@ Address._transformScript = function(script, network){
if (!script.constructor || (script.constructor.name && script.constructor.name !== 'Script')) {
throw new TypeError('Address must be an instance of Script.');
}
info.network = network || Networks.defaultNetwork;
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 = network || Networks.defaultNetwork;
return info;
};

View File

@ -8,6 +8,7 @@ var Hash = require('../crypto/hash');
var Opcode = require('../opcode');
var PublicKey = require('../publickey');
var Signature = require('../crypto/signature');
var Networks = require('../networks');
var $ = require('../util/preconditions');
var _ = require('lodash');
@ -213,7 +214,7 @@ Script.prototype.inspect = function() {
// script classification methods
/**
* @returns true if this is a pay to pubkey hash output script
* @returns {boolean} if this is a pay to pubkey hash output script
*/
Script.prototype.isPublicKeyHashOut = function() {
return !!(this.chunks.length === 5 &&
@ -225,7 +226,7 @@ Script.prototype.isPublicKeyHashOut = function() {
};
/**
* @returns true if this is a pay to public key hash input script
* @returns {boolean} if this is a pay to public key hash input script
*/
Script.prototype.isPublicKeyHashIn = function() {
return this.chunks.length === 2 &&
@ -241,7 +242,7 @@ Script.prototype.getPublicKeyHash = function() {
};
/**
* @returns true if this is a public key output script
* @returns {boolean} if this is a public key output script
*/
Script.prototype.isPublicKeyOut = function() {
return this.chunks.length === 2 &&
@ -251,7 +252,7 @@ Script.prototype.isPublicKeyOut = function() {
};
/**
* @returns true if this is a pay to public key input script
* @returns {boolean} if this is a pay to public key input script
*/
Script.prototype.isPublicKeyIn = function() {
return this.chunks.length === 1 &&
@ -261,7 +262,7 @@ Script.prototype.isPublicKeyIn = function() {
/**
* @returns true if this is a p2sh output script
* @returns {boolean} if this is a p2sh output script
*/
Script.prototype.isScriptHashOut = function() {
var buf = this.toBuffer();
@ -272,7 +273,7 @@ Script.prototype.isScriptHashOut = function() {
};
/**
* @returns true if this is a p2sh input script
* @returns {boolean} if this is a p2sh input script
* Note that these are frequently indistinguishable from pubkeyhashin
*/
Script.prototype.isScriptHashIn = function() {
@ -293,7 +294,7 @@ Script.prototype.isScriptHashIn = function() {
};
/**
* @returns true if this is a mutlsig output script
* @returns {boolean} if this is a mutlsig output script
*/
Script.prototype.isMultisigOut = function() {
return (this.chunks.length > 3 &&
@ -307,7 +308,7 @@ Script.prototype.isMultisigOut = function() {
/**
* @returns true if this is a multisig input script
* @returns {boolean} if this is a multisig input script
*/
Script.prototype.isMultisigIn = function() {
return this.chunks.length >= 2 &&
@ -320,7 +321,7 @@ Script.prototype.isMultisigIn = function() {
};
/**
* @returns true if this is an OP_RETURN data script
* @returns {boolean} if this is an OP_RETURN data script
*/
Script.prototype.isDataOut = function() {
return this.chunks.length >= 1 &&
@ -349,7 +350,7 @@ Script.prototype.getData = function() {
};
/**
* @returns true if the script is only composed of data pushing
* @returns {boolean} if the script is only composed of data pushing
* opcodes or small int opcodes (OP_0, OP_1, ..., OP_16)
*/
Script.prototype.isPushOnly = function() {
@ -397,7 +398,7 @@ Script.prototype.classify = function() {
/**
* @returns true if script is one of the known types
* @returns {boolean} if script is one of the known types
*/
Script.prototype.isStandard = function() {
// TODO: Add BIP62 compliance
@ -530,7 +531,7 @@ Script.prototype.removeCodeseparators = function() {
// high level script builder methods
/**
* @returns a new Multisig output script for given public keys,
* @returns {Script} a new Multisig output script for given public keys,
* requiring m of those public keys to spend
* @param {PublicKey[]} publicKeys - list of all public keys controlling the output
* @param {number} threshold - amount of required signatures to spend the output
@ -568,7 +569,7 @@ Script.buildMultisigOut = function(publicKeys, threshold, opts) {
* @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default)
* @param {Script=} opts.cachedMultisig don't recalculate the redeemScript
*
* @returns Script
* @returns {Script}
*/
Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) {
$.checkArgument(_.isArray(pubkeys));
@ -585,7 +586,7 @@ Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) {
};
/**
* @returns a new pay to public key hash output for the given
* @returns {Script} a new pay to public key hash output for the given
* address or public key
* @param {(Address|PublicKey)} to - destination address or public key
*/
@ -607,7 +608,7 @@ Script.buildPublicKeyHashOut = function(to) {
};
/**
* @returns a new pay to public key output for the given
* @returns {Script} a new pay to public key output for the given
* public key
*/
Script.buildPublicKeyOut = function(pubkey) {
@ -619,7 +620,7 @@ Script.buildPublicKeyOut = function(pubkey) {
};
/**
* @returns a new OP_RETURN script with data
* @returns {Script} a new OP_RETURN script with data
* @param {(string|Buffer)} to - the data to embed in the output
*/
Script.buildDataOut = function(data) {
@ -638,7 +639,7 @@ Script.buildDataOut = function(data) {
/**
* @param {Script|Address} script - the redeemScript for the new p2sh output.
* It can also be a p2sh address
* @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) {
$.checkArgument(script instanceof Script ||
@ -674,21 +675,21 @@ Script.buildPublicKeyHashIn = function(publicKey, signature, sigtype) {
};
/**
* @returns Script an empty script
* @returns {Script} an empty script
*/
Script.empty = function() {
return new Script();
};
/**
* @returns Script a new pay to script hash script that pays to this script
* @returns {Script} a new pay to script hash script that pays to this script
*/
Script.prototype.toScriptHashOut = function() {
return Script.buildScriptHashOut(this);
};
/**
* @return Script a script built from the address
* @return {Script} a script built from the address
*/
Script.fromAddress = function(address) {
address = Address(address);
@ -700,6 +701,18 @@ Script.fromAddress = function(address) {
throw new errors.Script.UnrecognizedAddress(address);
};
/**
* @return {Address} the associated address for this script
*/
Script.prototype.toAddress = function(network) {
network = Networks.get(network);
$.checkArgument(network, 'Must provide a network');
if (this.isPublicKeyHashOut() || this.isScriptHashOut()) {
return new Address(this, network);
}
throw new Error('The script type needs to be PayToPublicKeyHash or PayToScriptHash');
};
/**
* Analagous to bitcoind's FindAndDelete. Find and delete equivalent chunks,
* typically used with push data chunks. Note that this will find and delete
@ -725,8 +738,8 @@ Script.prototype.findAndDelete = function(script) {
};
/**
* @returns true if the chunk {i} is the smallest way to push that particular data.
* Comes from bitcoind's script interpreter CheckMinimalPush function
* @returns {boolean} if the chunk {i} is the smallest way to push that particular data.
*/
Script.prototype.checkMinimalPush = function(i) {
var chunk = this.chunks[i];

View File

@ -320,6 +320,7 @@ describe('Address', function() {
b.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX');
});
describe('from a script', function() {
it('should make this address from a script', function() {
var s = Script.fromString('OP_CHECKMULTISIG');
var buf = s.toBuffer();
@ -339,6 +340,18 @@ describe('Address', function() {
b.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7');
});
it('returns the same address if the script is a pay to public key hash out', function() {
var address = '16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX';
var script = Script.buildPublicKeyHashOut(new Address(address));
Address(script, Networks.livenet).toString().should.equal(address);
});
it('returns the same address if the script is a pay to script hash out', function() {
var address = '3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm';
var script = Script.buildScriptHashOut(new Address(address));
Address(script, Networks.livenet).toString().should.equal(address);
});
});
it('should derive from this known address string livenet', function() {
var address = new Address(str);
var buffer = address.toBuffer();

View File

@ -6,6 +6,7 @@ var bitcore = require('../..');
var BufferUtil = bitcore.util.buffer;
var Script = bitcore.Script;
var Networks = bitcore.Networks;
var Opcode = bitcore.Opcode;
var PublicKey = bitcore.PublicKey;
var Address = bitcore.Address;
@ -590,4 +591,24 @@ describe('Script', function() {
});
});
describe('toAddress', function() {
it('for a P2PKH address', function() {
var stringAddress = '1NaTVwXDDUJaXDQajoa9MqHhz4uTxtgK14';
var address = new Address(stringAddress);
var script = new Script(address);
script.toAddress(Networks.livenet).toString().should.equal(stringAddress);
});
it('for a P2SH address', function() {
var stringAddress = '3GhtMmAbWrUf6Y8vDxn9ETB14R6V7Br3mt';
var address = new Address(stringAddress);
var script = new Script(address);
script.toAddress(Networks.livenet).toString().should.equal(stringAddress);
});
it('fails if content is not recognized', function() {
expect(function() {
return Script().toAddress(Networks.livenet);
}).to.throw();
});
});
});