Merge pull request #567 from braydonf/address-interface

Address: Modified interface so that any instance of Address is valid
This commit is contained in:
Manuel Aráoz 2014-11-25 11:08:06 -03:00
commit 183d401992
2 changed files with 620 additions and 212 deletions

View File

@ -4,117 +4,350 @@ var base58check = require('./encoding/base58check');
var networks = require('./networks'); var networks = require('./networks');
var Hash = require('./crypto/hash'); var Hash = require('./crypto/hash');
function Address(buf) { /**
if (!(this instanceof Address)) *
return new Address(buf); * Bitcore Address
if (Buffer.isBuffer(buf)) { *
this.fromBuffer(buf); * Instantiate an address from an address String or Buffer, a public key or script hash Buffer,
} else if (typeof buf === 'string') { * or an instance of Pubkey or Script.
var str = buf; *
this.fromString(str); * @example
} else if (buf) { *
var obj = buf; * var address = new Address(keypair.pubkey, 'testnet').toString();
this.set(obj); *
* @param {String} data - The encoded data in various formats
* @param {String} [network] - The network: 'mainnet' or 'testnet'
* @param {String} [type] - The type of address: 'script' or 'pubkey'
* @returns {Address} A new valid and frozen instance of an Address
*/
function Address(data, network, type) {
if (!(this instanceof Address)) {
return new Address(data, network, type);
} }
}
Address.prototype.set = function(obj) { if (!data) {
this.hashbuf = obj.hashbuf || this.hashbuf || null; throw new TypeError('First argument is required, please include address data.');
this.networkstr = obj.networkstr || this.networkstr || 'mainnet'; }
this.typestr = obj.typestr || this.typestr || 'pubkeyhash';
return this;
};
Address.prototype.fromBuffer = function(buf) { if (network && (network !== 'mainnet' && network !== 'testnet')) {
if (buf.length !== 1 + 20) throw new TypeError('Second argument must be "mainnet" or "testnet".');
throw new Error('Address buffers must be exactly 21 bytes'); }
var version = buf[0];
if (version === networks['mainnet']['pubkeyhash']) { if (type && (type !== 'pubkeyhash' && type !== 'scripthash')) {
this.networkstr = 'mainnet'; throw new TypeError('Third argument must be "pubkeyhash" or "scripthash".');
this.typestr = 'pubkeyhash'; }
} else if (version === networks['mainnet']['scripthash']) {
this.networkstr = 'mainnet'; var info;
this.typestr = 'scripthash';
} else if (version === networks['testnet']['pubkeyhash']) { // transform and validate input data
this.networkstr = 'testnet'; if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 20) {
this.typestr = 'pubkeyhash'; info = Address._transformHash(data);
} else if (version === networks['testnet']['scripthash']) { } else if ((data instanceof Buffer || data instanceof Uint8Array) && data.length === 21) {
this.networkstr = 'testnet'; info = Address._transformBuffer(data, network, type);
this.typestr = 'scripthash'; } else if (data.constructor && (data.constructor.name && data.constructor.name === 'Pubkey')) {
info = Address._transformPubkey(data);
} else if (data.constructor && (data.constructor.name && data.constructor.name === 'Script')) {
info = Address._transformScript(data);
} else if (typeof(data) === 'string') {
info = Address._transformString(data, network, type);
} else { } else {
this.networkstr = 'unknown'; throw new TypeError('First argument is an unrecognized data format.');
this.typestr = 'unknown';
} }
this.hashbuf = buf.slice(1); // set defaults if not set
info.network = info.network || network || 'mainnet';
info.type = info.type || type || 'pubkeyhash';
// set the validated values
this.hashBuffer = info.hashBuffer;
this.network = info.network;
this.type = info.type;
return this; return this;
};
Address.prototype.fromHashbuf = function(hashbuf, networkstr, typestr) {
if (hashbuf.length !== 20)
throw new Error('hashbuf must be exactly 20 bytes');
this.hashbuf = hashbuf;
this.networkstr = networkstr || 'mainnet';
this.typestr = typestr || 'pubkeyhash';
return this;
};
Address.prototype.fromPubkey = function(pubkey, networkstr) {
this.hashbuf = Hash.sha256ripemd160(pubkey.toBuffer());
this.networkstr = networkstr || 'mainnet';
this.typestr = 'pubkeyhash';
return this;
};
Address.prototype.fromScript = function(script, networkstr) {
this.hashbuf = Hash.sha256ripemd160(script.toBuffer());
this.networkstr = networkstr || 'mainnet';
this.typestr = 'scripthash';
return this;
};
Address.prototype.fromString = function(str) {
var buf = base58check.decode(str);
return this.fromBuffer(buf);
} }
Address.isValid = function(addrstr) { /**
try { *
var address = new Address().fromString(addrstr); * Internal function to transform a hash buffer
} catch (e) { *
return false; * @param {Buffer} hash - An instance of a hash Buffer
* @returns {Object} An object with keys: hashBuffer
*/
Address._transformHash = function(hash){
var info = {};
if (!(hash instanceof Buffer) && !(hash instanceof Uint8Array)) {
throw new TypeError('Address supplied is not a buffer.');
} }
return address.isValid(); if (hash.length !== 20) {
throw new TypeError('Address hashbuffers must be exactly 20 bytes.');
}
info.hashBuffer = hash;
return info;
}; };
Address.prototype.isValid = function() { /**
try { *
this.validate(); * Internal function to transform a bitcoin address buffer
return true; *
} catch (e) { * @param {Buffer} buffer - An instance of a hex encoded address Buffer
return false; * @param {String} [network] - The network: 'mainnet' or 'testnet'
* @param {String} [type] - The type: 'pubkeyhash' or 'scripthash'
* @returns {Object} An object with keys: hashBuffer, network and type
*/
Address._transformBuffer = function(buffer, network, type){
var info = {};
if (!(buffer instanceof Buffer) && !(buffer instanceof Uint8Array)) {
throw new TypeError('Address supplied is not a buffer.');
} }
if (buffer.length !== 1 + 20) {
throw new TypeError('Address buffers must be exactly 21 bytes.');
}
var bufNetwork = false;
var bufType = false;
switch(buffer[0]){ // the version byte
case networks.mainnet.pubkeyhash:
bufNetwork = 'mainnet';
bufType = 'pubkeyhash';
break;
case networks.mainnet.scripthash:
bufNetwork = 'mainnet';
bufType = 'scripthash';
break;
case networks.testnet.pubkeyhash:
bufNetwork = 'testnet';
bufType = 'pubkeyhash';
break;
case networks.testnet.scripthash:
bufNetwork = 'testnet';
bufType = 'scripthash';
break;
}
if (!bufNetwork || (network && network !== bufNetwork)) {
throw new TypeError('Address has mismatched network type.');
}
if (!bufType || ( type && type !== bufType )) {
throw new TypeError('Address has mismatched type.');
}
info.hashBuffer = buffer.slice(1);
info.network = bufNetwork;
info.type = bufType;
return info;
}; };
/**
*
* Internal function to transform a Pubkey
*
* @param {Pubkey} pubkey - An instance of Pubkey
* @returns {Object} An object with keys: hashBuffer, type
*/
Address._transformPubkey = function(pubkey){
var info = {};
if (!pubkey.constructor || (pubkey.constructor.name && pubkey.constructor.name !== 'Pubkey')) {
throw new TypeError('Address must be an instance of Pubkey.');
}
info.hashBuffer = Hash.sha256ripemd160(pubkey.toBuffer());
info.type = 'pubkeyhash';
return info;
};
/**
*
* Internal function to transform a Script
*
* @param {Script} script - An instance of Script
* @returns {Object} An object with keys: hashBuffer, type
*/
Address._transformScript = function(script){
var info = {};
if (!script.constructor || (script.constructor.name && script.constructor.name !== 'Script')) {
throw new TypeError('Address must be an instance of Script.');
}
info.hashBuffer = Hash.sha256ripemd160(script.toBuffer());
info.type = 'scripthash';
return info;
};
/**
*
* Internal function to transform a bitcoin address string
*
* @param {String} data - An instance of Pubkey
* @param {String} [network] - The network: 'mainnet' or 'testnet'
* @param {String} [type] - The type: 'pubkeyhash' or 'scripthash'
* @returns {Object} An object with keys: hashBuffer, network and type
*/
Address._transformString = function(data, network, type){
if( typeof(data) !== 'string' ) {
throw new TypeError('Address supplied is not a string.');
}
var addressBuffer = base58check.decode(data);
var info = Address._transformBuffer(addressBuffer, network, type);
return info;
};
/**
*
* Instantiate an address from a Pubkey instance
*
* @param {String} data - An instance of Pubkey
* @param {String} network - The network: 'mainnet' or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromPubkey = function(data, network){
var info = Address._transformPubkey(data);
return new Address(info.hashBuffer, network, info.type);
};
/**
*
* Instantiate an address from a ripemd160 public key hash
*
* @param {Buffer} hash - An instance of buffer of the hash
* @param {String} network - The network: 'mainnet' or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromPubkeyHash = function(hash, network) {
var info = Address._transformHash(hash);
return new Address(info.hashBuffer, network, 'pubkeyhash');
};
/**
*
* Instantiate an address from a ripemd160 script hash
*
* @param {Buffer} hash - An instance of buffer of the hash
* @param {String} network - The network: 'mainnet' or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromScriptHash = function(hash, network) {
var info = Address._transformHash(hash);
return new Address(info.hashBuffer, network, 'scripthash');
};
/**
*
* Instantiate an address from a Script
*
* @param {Script} script - An instance of Script
* @param {String} network - The network: 'mainnet' or 'testnet'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromScript = function(script, network) {
var info = Address._transformScript(script);
return new Address(info.hashBuffer, network, info.type);
};
/**
*
* Instantiate an address from a buffer of the address
*
* @param {Buffer} buffer - An instance of buffer of the address
* @param {String} [network] - The network: 'mainnet' or 'testnet'
* @param {String} [type] - The type of address: 'script' or 'pubkey'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromBuffer = function(buffer, network, type) {
var info = Address._transformBuffer(buffer, network, type);
return new Address(info.hashBuffer, info.network, info.type);
};
/**
*
* Instantiate an address from an address string
*
* @param {String} str - An string of the bitcoin address
* @param {String} [network] - The network: 'mainnet' or 'testnet'
* @param {String} [type] - The type of address: 'script' or 'pubkey'
* @returns {Address} A new valid and frozen instance of an Address
*/
Address.fromString = function(str, network, type) {
var info = Address._transformString(str, network, type);
return new Address(info.hashBuffer, info.network, info.type);
};
/**
*
* Will return a validation error if exists
*
* @example
*
* var error = Address.getValidationError('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'testnet');
* // a network mismatch error
*
* @param {String} data - The encoded data
* @param {String} network - The network: 'mainnet' or 'testnet'
* @param {String} type - The type of address: 'script' or 'pubkey'
* @returns {null|Error} The corresponding error message
*/
Address.getValidationError = function(data, network, type) {
var error;
try {
new Address(data, network, type);
} catch (e) {
error = e;
}
return error;
};
/**
*
* Will return a boolean if an address is valid
*
* @example
*
* var valid = Address.isValid('15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2', 'mainnet');
* // true
*
* @param {String} data - The encoded data
* @param {String} network - The network: 'mainnet' or 'testnet'
* @param {String} type - The type of address: 'script' or 'pubkey'
* @returns {null|Error} The corresponding error message
*/
Address.isValid = function(data, network, type) {
return !Address.getValidationError(data, network, type);
};
/**
*
* Will return a buffer representation of the address
*
* @returns {Buffer} Bitcoin address buffer
*/
Address.prototype.toBuffer = function() { Address.prototype.toBuffer = function() {
var version = new Buffer([networks[this.networkstr][this.typestr]]); var version = new Buffer([networks[this.network][this.type]]);
var buf = Buffer.concat([version, this.hashbuf]); var buf = Buffer.concat([version, this.hashBuffer]);
return buf; return buf;
}; };
/**
*
* Will return a the string representation of the address
*
* @returns {String} Bitcoin address
*/
Address.prototype.toString = function() { Address.prototype.toString = function() {
return base58check.encode(this.toBuffer()); return base58check.encode(this.toBuffer());
}; };
Address.prototype.validate = function() { /**
if (!Buffer.isBuffer(this.hashbuf) || this.hashbuf.length !== 20) *
throw new Error('hash must be a buffer of 20 bytes'); * Will return a string formatted for the console
if (this.networkstr !== 'mainnet' && this.networkstr !== 'testnet') *
throw new Error('networkstr must be "mainnet" or "testnet"'); * @returns {String} Bitcoin address
if (this.typestr !== 'pubkeyhash' && this.typestr !== 'scripthash') */
throw new Error('typestr must be "pubkeyhash" or "scripthash"'); Address.prototype.inspect = function() {
return this; return '<Address: ' + this.toString() + ', type: '+this.type+', network: '+this.network+'>';
}; }
module.exports = Address; module.exports = Address;

View File

@ -8,149 +8,329 @@ var Address = bitcore.Address;
var Script = bitcore.Script; var Script = bitcore.Script;
describe('Address', function() { describe('Address', function() {
var pubkeyhash = new Buffer('3c3fa3d4adcaf8f52d5b1843975e122548269937', 'hex'); var pubkeyhash = new Buffer('3c3fa3d4adcaf8f52d5b1843975e122548269937', 'hex');
var buf = Buffer.concat([new Buffer([0]), pubkeyhash]); var buf = Buffer.concat([new Buffer([0]), pubkeyhash]);
var str = '16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r'; var str = '16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r';
var strTest = 'n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X';
it('should create a new address object', function() { it('should throw an error because of missing data', function() {
var address = new Address(); (function() {
should.exist(address); var a = new Address();
address = new Address(buf); }).should.throw('First argument is required, please include address data.');
should.exist(address);
address = new Address(str);
should.exist(address);
}); });
describe('@isValid', function() { it('should throw an error because of bad network param', function() {
(function(){
var a = new Address(validAddresses[0], 'main', 'pubkeyhash');
}).should.throw('Second argument must be "mainnet" or "testnet".');
});
it('should validate this valid address string', function() { it('should throw an error because of bad type param', function() {
Address.isValid(str).should.equal(true); (function() {
var a = new Address(validAddresses[0], 'mainnet', 'pubkey');
}).should.throw('Third argument must be "pubkeyhash" or "scripthash"');
});
// mainnet valid
var validAddresses = [
'15vkcKf7gB23wLAnZLmbVuMiiVDc1Nm4a2',
'1A6ut1tWnUq1SEQLMr4ttDh24wcbJ5o9TT',
'1BpbpfLdY7oBS9gK7aDXgvMgr1DPvNhEB2',
'1Jz2yCRd5ST1p2gUqFB5wsSQfdm3jaFfg7'
];
// mainnet p2sh
var validp2shAddresses = [
'342ftSRCvFHfCeFFBuz4xwbeqnDw6BGUey',
'33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk',
'37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3',
'3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy'
];
// testnet p2sh
var testValidp2shAddresses = [
'2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C',
'2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda',
'2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN',
'2NB72XtkjpnATMggui83aEtPawyyKvnbX2o'
];
//mainnet bad checksums
var badChecksums = [
'15vkcKf7gB23wLAnZLmbVuMiiVDc3nq4a2',
'1A6ut1tWnUq1SEQLMr4ttDh24wcbj4w2TT',
'1BpbpfLdY7oBS9gK7aDXgvMgr1DpvNH3B2',
'1Jz2yCRd5ST1p2gUqFB5wsSQfdmEJaffg7'
];
//mainnet non-base58
var nonBase58 = [
'15vkcKf7g#23wLAnZLmb$uMiiVDc3nq4a2',
'1A601ttWnUq1SEQLMr4ttDh24wcbj4w2TT',
'1BpbpfLdY7oBS9gK7aIXgvMgr1DpvNH3B2',
'1Jz2yCRdOST1p2gUqFB5wsSQfdmEJaffg7'
];
//testnet valid
var testValidAddresses = [
'n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X',
'n45x3R2w2jaSC62BMa9MeJCd3TXxgvDEmm',
'mursDVxqNQmmwWHACpM9VHwVVSfTddGsEM',
'mtX8nPZZdJ8d3QNLRJ1oJTiEi26Sj6LQXS'
];
describe('validation', function() {
it('should describe this mainnet address as an invalid testnet address', function() {
var error = Address.getValidationError('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'testnet');
should.exist(error);
}); });
it('should invalidate this valid address string', function() { it('should should return a true boolean', function(){
Address.isValid(str.substr(1)).should.equal(false); var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'mainnet');
valid.should.equal(true);
});
it('should should return a false boolean', function(){
var valid = Address.isValid('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo', 'testnet');
valid.should.equal(false);
});
it('should validate addresses', function() {
for(var i=0;i<validAddresses.length;i++){
var error = Address.getValidationError(validAddresses[i]);
should.not.exist(error);
}
});
it('should validate p2sh addresses', function() {
for(var i=0;i<validp2shAddresses.length;i++){
var error = Address.getValidationError(validp2shAddresses[i]);
should.not.exist(error);
}
});
it('should validate testnet p2sh addresses', function() {
for(var i=0;i<testValidp2shAddresses.length;i++){
var error = Address.getValidationError(testValidp2shAddresses[i], 'testnet');
should.not.exist(error);
}
});
it('should not validate addresses with params', function() {
for(var i=0;i<validAddresses.length;i++){
var error = Address.getValidationError(validAddresses[i], 'testnet');
should.exist(error);
}
});
it('should validate addresses with params', function() {
for(var i=0;i<validAddresses.length;i++){
var error = Address.getValidationError(validAddresses[i], 'mainnet');
should.not.exist(error);
}
});
it('should not validate because of an invalid checksum', function() {
for(var i=0;i<badChecksums.length;i++){
var error = Address.getValidationError(badChecksums[i], 'mainnet', 'pubkeyhash');
should.exist(error);
error.message.should.equal('Checksum mismatch');
}
});
it('should not validate because of mismatched network', function() {
for(var i=0;i<validAddresses.length;i++){
var error = Address.getValidationError(validAddresses[i], 'testnet', 'pubkeyhash');
should.exist(error);
error.message.should.equal('Address has mismatched network type.');
}
});
it('should not validate because of a mismatched type', function() {
for(var i=0;i<validAddresses.length;i++){
var error = Address.getValidationError(validAddresses[i], 'mainnet', 'scripthash');
should.exist(error);
error.message.should.equal('Address has mismatched type.');
}
});
it('should not validate because of non-base58 characters', function() {
for(var i=0;i<nonBase58.length;i++){
var error = Address.getValidationError(nonBase58[i], 'mainnet', 'pubkeyhash');
should.exist(error);
error.message.should.equal('Non-base58 character');
}
});
it('should not validate addresses', function() {
for(var i=0;i<badChecksums.length;i++){
var error = Address.getValidationError(badChecksums[i]);
should.exist(error);
}
});
it('should validate testnet addresses', function() {
for(var i=0;i<testValidAddresses.length;i++){
var error = Address.getValidationError(testValidAddresses[i], 'testnet');
should.not.exist(error);
}
});
it('should not validate testnet addresses because of mismatched network', function() {
for(var i=0;i<testValidAddresses.length;i++){
var error = Address.getValidationError(testValidAddresses[i], 'mainnet', 'pubkeyhash');
should.exist(error);
error.message.should.equal('Address has mismatched network type.');
}
}); });
}); });
describe('#fromBuffer', function() { describe('encodings', function() {
it('should make an address from a buffer', function() { it('should make an address from a buffer', function() {
Address().fromBuffer(buf).toString().should.equal(str); var a = Address.fromBuffer(buf).toString().should.equal(str);
var b = new Address(buf).toString().should.equal(str);
var c = Address(buf).toString().should.equal(str);
}); });
}); it('should make an address from a string', function() {
var a = Address.fromString(str).toString().should.equal(str);
describe('#fromHashbuf', function() { var b = new Address(str).toString().should.equal(str);
it('should make an address from a hashbuf', function() {
Address().fromHashbuf(pubkeyhash).toString().should.equal(str);
var a = Address().fromHashbuf(pubkeyhash, 'testnet', 'scripthash');
a.networkstr.should.equal('testnet');
a.typestr.should.equal('scripthash');
}); });
it('should throw an error for invalid length hashbuf', function() { it('should error because of unrecognized data format', function() {
(function() { (function() {
Address().fromHashbuf(buf); var a = new Address(new Error());
}).should.throw('hashbuf must be exactly 20 bytes'); }).should.throw('First argument is an unrecognized data format.');
}); });
}); it('should error because of incorrect format for pubkey hash', function() {
(function() {
var a = new Address.fromPubkeyHash('notahash');
}).should.throw('Address supplied is not a buffer.');
});
describe('#fromPubkey', function() { it('should error because of incorrect format for script hash', function() {
(function() {
var a = new Address.fromScriptHash('notascript');
}).should.throw('Address supplied is not a buffer.');
});
it('should make this address from a compressed pubkey', function() { it('should error because of incorrect type for transform buffer', function() {
(function() {
var info = Address._transformBuffer('notabuffer');
}).should.throw('Address supplied is not a buffer.');
});
it('should error because of incorrect length buffer for transform buffer', function() {
(function() {
var info = Address._transformBuffer(new Buffer(20));
}).should.throw('Address buffers must be exactly 21 bytes.');
});
it('should error because of incorrect type for pubkey transform', function() {
(function() {
var info = Address._transformPubkey(new Buffer(20));
}).should.throw('Address must be an instance of Pubkey.');
});
it('should error because of incorrect type for script transform', function() {
(function() {
var info = Address._transformScript(new Buffer(20));
}).should.throw('Address must be an instance of Script.');
});
it('should error because of incorrect type for string transform', function() {
(function() {
var info = Address._transformString(new Buffer(20));
}).should.throw('Address supplied is not a string.');
});
it('should make an address from a pubkey hash buffer', function() {
var hash = pubkeyhash; //use the same hash
var a = Address.fromPubkeyHash(hash).toString().should.equal(str);
var b = Address.fromPubkeyHash(hash, 'testnet');
b.network.should.equal('testnet');
b.type.should.equal('pubkeyhash');
var c = new Address(hash).toString().should.equal(str);
});
it('should throw an error for invalid length hashBuffer', function() {
(function() {
var a = Address.fromPubkeyHash(buf);
}).should.throw('Address hashbuffers must be exactly 20 bytes.');
});
it('should make this address from a compressed pubkey object', function() {
var pubkey = new Pubkey(); var pubkey = new Pubkey();
pubkey.fromDER(new Buffer('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004', 'hex')); pubkey.fromDER(new Buffer('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004',
var address = new Address(); 'hex'));
address.fromPubkey(pubkey); var a = Address.fromPubkey(pubkey);
address.toString().should.equal('19gH5uhqY6DKrtkU66PsZPUZdzTd11Y7ke'); a.toString().should.equal('19gH5uhqY6DKrtkU66PsZPUZdzTd11Y7ke');
var b = new Address(pubkey);
b.toString().should.equal('19gH5uhqY6DKrtkU66PsZPUZdzTd11Y7ke');
}); });
it('should make this address from an uncompressed pubkey', function() { it('should make this address from an uncompressed pubkey', function() {
var pubkey = new Pubkey(); var pubkey = new Pubkey();
pubkey.fromDER(new Buffer('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004', 'hex')); pubkey.fromDER(new Buffer('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004',
var address = new Address(); 'hex'));
pubkey.compressed = false; pubkey.compressed = false;
address.fromPubkey(pubkey, 'mainnet'); var a = Address.fromPubkey(pubkey, 'mainnet', 'pubkeyhash');
address.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX'); a.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX');
var b = new Address(pubkey, 'mainnet', 'pubkeyhash');
b.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX');
}); });
});
describe('#fromScript', function() {
it('should make this address from a script', function() { it('should make this address from a script', function() {
var script = Script().fromString("OP_CHECKMULTISIG"); var s = Script().fromString("OP_CHECKMULTISIG");
var address = Address().fromScript(script); var buf = s.toBuffer();
address.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); var a = Address.fromScript(s);
a.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm');
var b = new Address(s);
b.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm');
var c = Address.fromScriptHash(bitcore.crypto.Hash.sha256ripemd160(buf));
c.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm');
}); });
it('should make this address from other script', function() { it('should make this address from other script', function() {
var script = Script().fromString("OP_CHECKSIG OP_HASH160"); var s = Script().fromString("OP_CHECKSIG OP_HASH160");
var address = Address().fromScript(script); var a = Address.fromScript(s);
address.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7'); a.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7');
var b = new Address(s);
b.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7');
}); });
});
describe('#fromString', function() {
it('should derive from this known address string mainnet', function() { it('should derive from this known address string mainnet', function() {
var address = new Address(); var address = new Address(str);
address.fromString(str); var buffer = address.toBuffer();
address.toBuffer().slice(1).toString('hex').should.equal(pubkeyhash.toString('hex')); var slice = buffer.slice(1);
var sliceString = slice.toString('hex')
sliceString.should.equal(pubkeyhash.toString('hex'));
}); });
it('should derive from this known address string testnet', function() { it('should derive from this known address string testnet', function() {
var address = new Address(); var a = new Address(testValidAddresses[0], 'testnet');
address.fromString(str); var b = new Address(a.toString());
address.networkstr = 'testnet'; b.toString().should.equal(testValidAddresses[0]);
address.fromString(address.toString()); b.network.should.equal('testnet');
address.toString().should.equal('mm1X5M2QWyHVjn7txrF7mmtZDpjCXzoa98');
}); });
it('should derive from this known address string mainnet scripthash', function() { it('should derive from this known address string mainnet scripthash', function() {
var address = new Address(); var a = new Address(validp2shAddresses[0], 'mainnet', 'scripthash');
address.fromString(str); var b = new Address(a.toString());
address.networkstr = 'mainnet'; b.toString().should.equal(validp2shAddresses[0]);
address.typestr = 'scripthash';
address.fromString(address.toString());
address.toString().should.equal('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo');
}); });
it('should derive from this known address string testnet scripthash', function() { it('should derive from this known address string testnet scripthash', function() {
var address = new Address(); var address = new Address(testValidp2shAddresses[0], 'testnet', 'scripthash');
address.fromString(str); address = new Address(address.toString());
address.networkstr = 'testnet'; address.toString().should.equal(testValidp2shAddresses[0]);
address.typestr = 'scripthash';
address.fromString(address.toString());
address.toString().should.equal('2MxjnmaMtsJfyFcyG3WZCzS2RihdNuWqeX4');
});
});
describe('#isValid', function() {
it('should describe this valid address as valid', function() {
var address = new Address();
address.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo');
address.isValid().should.equal(true);
});
it('should describe this address with unknown network as invalid', function() {
var address = new Address();
address.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo');
address.networkstr = 'unknown';
address.isValid().should.equal(false);
});
it('should describe this address with unknown type as invalid', function() {
var address = new Address();
address.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo');
address.typestr = 'unknown';
address.isValid().should.equal(false);
}); });
}); });
@ -158,47 +338,42 @@ describe('Address', function() {
describe('#toBuffer', function() { describe('#toBuffer', function() {
it('should output this known hash', function() { it('should output this known hash', function() {
var address = new Address(); var address = new Address(str);
address.fromString(str);
address.toBuffer().slice(1).toString('hex').should.equal(pubkeyhash.toString('hex')); address.toBuffer().slice(1).toString('hex').should.equal(pubkeyhash.toString('hex'));
}); });
}); });
describe('#toString', function() { describe('#toString', function() {
it('should output the same thing that was input', function() { it('should output a mainnet pubkeyhash address', function() {
var address = new Address(); var address = new Address(str);
address.fromString(str);
address.toString().should.equal(str); address.toString().should.equal(str);
}); });
it('should output a scripthash address', function() {
var address = new Address(validp2shAddresses[0]);
address.toString().should.equal(validp2shAddresses[0]);
});
it('should output a testnet scripthash address', function() {
var address = new Address(testValidp2shAddresses[0]);
address.toString().should.equal(testValidp2shAddresses[0]);
});
it('should output a testnet pubkeyhash address', function() {
var address = new Address(testValidAddresses[0]);
address.toString().should.equal(testValidAddresses[0]);
});
}); });
describe('#validate', function() { describe('#inspect', function() {
it('should not throw an error on this valid address', function() {
var address = new Address();
address.fromString(str);
should.exist(address.validate());
});
it('should throw an error on this invalid network', function() { it('should output formatted output correctly', function() {
var address = new Address(); var address = new Address(str);
address.fromString(str); var output = '<Address: 16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r, type: pubkeyhash, network: mainnet>';
address.networkstr = 'unknown'; address.inspect().should.equal(output);
(function() {
address.validate();
}).should.throw('networkstr must be "mainnet" or "testnet"');
});
it('should throw an error on this invalid type', function() {
var address = new Address();
address.fromString(str);
address.typestr = 'unknown';
(function() {
address.validate();
}).should.throw('typestr must be "pubkeyhash" or "scripthash"');
}); });
}); });