Merge pull request #567 from braydonf/address-interface
Address: Modified interface so that any instance of Address is valid
This commit is contained in:
commit
183d401992
405
lib/address.js
405
lib/address.js
|
@ -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) {
|
/**
|
||||||
|
*
|
||||||
|
* Internal function to transform a hash buffer
|
||||||
|
*
|
||||||
|
* @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.');
|
||||||
|
}
|
||||||
|
if (hash.length !== 20) {
|
||||||
|
throw new TypeError('Address hashbuffers must be exactly 20 bytes.');
|
||||||
|
}
|
||||||
|
info.hashBuffer = hash;
|
||||||
|
return info;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Internal function to transform a bitcoin address buffer
|
||||||
|
*
|
||||||
|
* @param {Buffer} buffer - An instance of a hex encoded address Buffer
|
||||||
|
* @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 {
|
try {
|
||||||
var address = new Address().fromString(addrstr);
|
new Address(data, network, type);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
error = e;
|
||||||
}
|
}
|
||||||
return address.isValid();
|
return error;
|
||||||
};
|
};
|
||||||
|
|
||||||
Address.prototype.isValid = function() {
|
/**
|
||||||
try {
|
*
|
||||||
this.validate();
|
* Will return a boolean if an address is valid
|
||||||
return true;
|
*
|
||||||
} catch (e) {
|
* @example
|
||||||
return false;
|
*
|
||||||
}
|
* 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;
|
||||||
|
|
415
test/address.js
415
test/address.js
|
@ -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(){
|
||||||
it('should validate this valid address string', function() {
|
var a = new Address(validAddresses[0], 'main', 'pubkeyhash');
|
||||||
Address.isValid(str).should.equal(true);
|
}).should.throw('Second argument must be "mainnet" or "testnet".');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should invalidate this valid address string', function() {
|
it('should throw an error because of bad type param', function() {
|
||||||
Address.isValid(str.substr(1)).should.equal(false);
|
(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 should return a true boolean', function(){
|
||||||
|
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);
|
||||||
|
var b = new Address(str).toString().should.equal(str);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#fromHashbuf', function() {
|
it('should error because of unrecognized data format', function() {
|
||||||
|
|
||||||
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() {
|
|
||||||
(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,8 +338,7 @@ 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'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -167,38 +346,34 @@ describe('Address', function() {
|
||||||
|
|
||||||
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]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#validate', function() {
|
it('should output a testnet scripthash address', function() {
|
||||||
|
var address = new Address(testValidp2shAddresses[0]);
|
||||||
it('should not throw an error on this valid address', function() {
|
address.toString().should.equal(testValidp2shAddresses[0]);
|
||||||
var address = new Address();
|
|
||||||
address.fromString(str);
|
|
||||||
should.exist(address.validate());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error on this invalid network', function() {
|
it('should output a testnet pubkeyhash address', function() {
|
||||||
var address = new Address();
|
var address = new Address(testValidAddresses[0]);
|
||||||
address.fromString(str);
|
address.toString().should.equal(testValidAddresses[0]);
|
||||||
address.networkstr = 'unknown';
|
|
||||||
(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);
|
describe('#inspect', function() {
|
||||||
address.typestr = 'unknown';
|
|
||||||
(function() {
|
it('should output formatted output correctly', function() {
|
||||||
address.validate();
|
var address = new Address(str);
|
||||||
}).should.throw('typestr must be "pubkeyhash" or "scripthash"');
|
var output = '<Address: 16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r, type: pubkeyhash, network: mainnet>';
|
||||||
|
address.inspect().should.equal(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue