Address: Added documentation and refactored to accept both a string and network object.

This commit is contained in:
Braydon Fuller 2014-12-09 16:14:55 -05:00
parent 1dfb7f1d02
commit 3b061b057f
5 changed files with 118 additions and 75 deletions

View File

@ -4,6 +4,44 @@ Represents a bitcoin Address. Addresses became the most popular way to make
bitcoin transactions. See [the official Bitcoin
Wiki](https://en.bitcoin.it/wiki/Address) for more information.
## Instantiate an Address
To be able to receive bitcoin an address is needed, here is how to create an
address from a new private key. Please see the [`PrivateKey`](PrivateKey.md) docs
for more information about exporting and saving a key.
```javascript
var PrivateKey = require('bitcore/lib/privatekey');
var privateKey = new PrivateKey();
var address = privateKey.toAddress();
```
You can also instantiate an address from a String or PublicKey.
```javascript
var Address = require('bitcore/lib/address');
var PublicKey = require('bitcore/lib/publickey');
var Networks = require('bitcore/lib/networks');
// from a string
var address = Address.fromString('mwkXG8NnB2snbqWTcpNiK6qqGHm1LebHDc');
// a default network address from a public key
var publicKey = PublicKey(privateKey);
var address = Address.fromPublicKey(publicKey);
// a testnet address from a public key
var publicKey = PublicKey(privateKey);
var address = Address.fromPublicKey(publicKey, Networks.testnet);
```
## Validating an Address
The main use that we expect you'll have for the `Address` class in bitcore is
validating that an address is a valid one, what type of address it is (you may
be interested on knowning if the address is a simple "pay to public key hash"
@ -13,18 +51,21 @@ belong to.
The code to do these validations looks like this:
```javascript
var address = new bitcore.Address('1BitcoinAddress...');
assert(address.network === bitcore.network.livenet);
// Detect the kind of the address...
assert(address.scriptType === bitcore.Address.Pay2PubKeyHash);
```
// validate that an input field is a valid testnet address
if (Address.isValid(input, Networks.testnet){
...
}
There are also static methods for this that work very similarly:
// validate that an input field is a valid livenet pubkeyhash
if (Address.isValid(input, Networks.livenet, Address.Pay2PubKeyHash){
...
}
// get the specific validation error that can occurred
var error = Address.getValidationError(input, Networks.testnet);
if (error) {
// handle the error
}
}
```javascript
var address = new bitcore.Address();
assert(bitcore.Address.isValid('1BitcoinAddress...'));
assert(bitcore.Address.network('1BitcoinAddress...') === bitcore.network.livenet);
assert(bitcore.Address.scriptType('1BitcoinAddress...') !== bitcore.Address.Pay2ScriptHash);
assert(bitcore.Address.scriptType('3MultisigP2SH...') === bitcore.Address.Pay2ScriptHash);
```

View File

@ -1,11 +1,10 @@
'use strict';
var base58check = require('./encoding/base58check');
var networks = require('./networks');
var Networks = require('./networks');
var Hash = require('./crypto/hash');
/**
*
* Instantiate an address from an address String or Buffer, a public key or script hash Buffer,
* or an instance of PublicKey or Script.
*
@ -40,7 +39,7 @@ function Address(data, network, type) {
throw new TypeError('First argument is required, please include address data.');
}
if (network && !networks.get(network)) {
if (network && !Networks.get(network)) {
throw new TypeError('Second argument must be "livenet" or "testnet".');
}
@ -68,7 +67,7 @@ function Address(data, network, type) {
}
// set defaults if not set
info.network = info.network || network || networks.defaultNetwork.name;
info.network = info.network || Networks.get(network) || Networks.defaultNetwork;
info.type = info.type || type || Address.PayToPublicKeyHash;
Object.defineProperty(this, 'hashBuffer', {
@ -93,7 +92,6 @@ Address.PayToPublicKeyHash = 'pubkeyhash';
Address.PayToScriptHash = 'scripthash';
/**
*
* Internal function to transform a hash buffer
*
* @param {Buffer} hash - An instance of a hash Buffer
@ -113,7 +111,39 @@ Address._transformHash = function(hash){
};
/**
* Internal function to discover the network and type
*
* @param {Buffer} buffer - An instance of a hex encoded address Buffer
* @returns {Object} An object with keys: network and type
* @private
*/
Address._discoverMeta = function(buffer){
var meta = {};
switch(buffer[0]){ // the version byte
case Networks.livenet.pubkeyhash:
meta.network = Networks.livenet;
meta.type = Address.PayToPublicKeyHash;
break;
case Networks.livenet.scripthash:
meta.network = Networks.livenet;
meta.type = Address.PayToScriptHash;
break;
case Networks.testnet.pubkeyhash:
meta.network = Networks.testnet;
meta.type = Address.PayToPublicKeyHash;
break;
case Networks.testnet.scripthash:
meta.network = Networks.testnet;
meta.type = Address.PayToScriptHash;
break;
}
return meta;
};
/**
* Internal function to transform a bitcoin address buffer
*
* @param {Buffer} buffer - An instance of a hex encoded address Buffer
@ -131,47 +161,24 @@ Address._transformBuffer = function(buffer, network, type){
throw new TypeError('Address buffers must be exactly 21 bytes.');
}
var bufNetwork = false;
var bufType = false;
network = Networks.get(network);
var meta = Address._discoverMeta(buffer);
switch(buffer[0]){ // the version byte
case networks.livenet.pubkeyhash:
bufNetwork = 'livenet';
bufType = 'pubkeyhash';
break;
case networks.livenet.scripthash:
bufNetwork = 'livenet';
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)) {
if (!meta.network || (network && network !== meta.network)) {
throw new TypeError('Address has mismatched network type.');
}
if (!bufType || ( type && type !== bufType )) {
if (!meta.type || ( type && type !== meta.type )) {
throw new TypeError('Address has mismatched type.');
}
info.hashBuffer = buffer.slice(1);
info.network = bufNetwork;
info.type = bufType;
info.network = meta.network;
info.type = meta.type;
return info;
};
/**
*
* Internal function to transform a PublicKey
*
* @param {PublicKey} pubkey - An instance of PublicKey
@ -189,7 +196,6 @@ Address._transformPublicKey = function(pubkey){
};
/**
*
* Internal function to transform a Script
*
* @param {Script} script - An instance of Script
@ -207,7 +213,6 @@ Address._transformScript = function(script){
};
/**
*
* Internal function to transform a bitcoin address string
*
* @param {String} data - An instance of PublicKey
@ -226,7 +231,6 @@ Address._transformString = function(data, network, type){
};
/**
*
* Instantiate an address from a PublicKey instance
*
* @param {PublicKey} data - An instance of PublicKey
@ -235,12 +239,11 @@ Address._transformString = function(data, network, type){
*/
Address.fromPublicKey = function(data, network){
var info = Address._transformPublicKey(data);
network = network || networks.defaultNetwork.name;
network = network || Networks.defaultNetwork;
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
@ -253,7 +256,6 @@ Address.fromPublicKeyHash = function(hash, network) {
};
/**
*
* Instantiate an address from a ripemd160 script hash
*
* @param {Buffer} hash - An instance of buffer of the hash
@ -266,7 +268,6 @@ Address.fromScriptHash = function(hash, network) {
};
/**
*
* Instantiate an address from a Script
*
* @param {Script} script - An instance of Script
@ -279,7 +280,6 @@ Address.fromScript = function(script, network) {
};
/**
*
* Instantiate an address from a buffer of the address
*
* @param {Buffer} buffer - An instance of buffer of the address
@ -293,7 +293,6 @@ Address.fromBuffer = function(buffer, network, type) {
};
/**
*
* Instantiate an address from an address string
*
* @param {String} str - An string of the bitcoin address
@ -307,7 +306,6 @@ Address.fromString = function(str, network, type) {
};
/**
*
* Will return a validation error if exists
*
* @example
@ -331,7 +329,6 @@ Address.getValidationError = function(data, network, type) {
};
/**
*
* Will return a boolean if an address is valid
*
* @example
@ -365,19 +362,17 @@ Address.prototype.isPayToScriptHash = function() {
};
/**
*
* Will return a buffer representation of the address
*
* @returns {Buffer} Bitcoin address buffer
*/
Address.prototype.toBuffer = function() {
var version = new Buffer([networks[this.network][this.type]]);
var version = new Buffer([this.network[this.type]]);
var buf = Buffer.concat([version, this.hashBuffer]);
return buf;
};
/**
*
* Will return a the string representation of the address
*
* @returns {String} Bitcoin address
@ -387,7 +382,6 @@ Address.prototype.toString = function() {
};
/**
*
* Will return a string formatted for the console
*
* @returns {String} Bitcoin address

View File

@ -9,6 +9,10 @@ var _ = require('lodash');
*/
function Network() {}
Network.prototype.toString = function toString() {
return this.name;
};
/**
* @instance
* @member Network#livenet

View File

@ -8,7 +8,7 @@ var bitcore = require('..');
var PublicKey = bitcore.PublicKey;
var Address = bitcore.Address;
var Script = bitcore.Script;
var networks = bitcore.Networks;
var Networks = bitcore.Networks;
describe('Address', function() {
@ -205,6 +205,10 @@ describe('Address', function() {
new Address(str).toString().should.equal(str);
});
it('should make an address using a non-string network', function() {
Address.fromString(str, Networks.livenet).toString().should.equal(str);
});
it('should error because of unrecognized data format', function() {
(function() {
return new Address(new Error());
@ -257,7 +261,7 @@ describe('Address', function() {
var hash = pubkeyhash; //use the same hash
Address.fromPublicKeyHash(hash).toString().should.equal(str);
var b = Address.fromPublicKeyHash(hash, 'testnet');
b.network.should.equal('testnet');
b.network.should.equal(Networks.testnet);
b.type.should.equal('pubkeyhash');
new Address(hash).toString().should.equal(str);
});
@ -265,13 +269,13 @@ describe('Address', function() {
it('should make an address using the default network', function() {
var hash = pubkeyhash; //use the same hash
var a = Address.fromPublicKeyHash(hash);
a.network.should.equal('livenet');
a.network.should.equal(Networks.livenet);
// change the default
networks.defaultNetwork = networks.testnet;
Networks.defaultNetwork = Networks.testnet;
var b = Address.fromPublicKeyHash(hash);
b.network.should.equal('testnet');
b.network.should.equal(Networks.testnet);
// restore the default
networks.defaultNetwork = networks.livenet;
Networks.defaultNetwork = Networks.livenet;
});
it('should throw an error for invalid length hashBuffer', function() {
@ -325,7 +329,7 @@ describe('Address', function() {
var a = new Address(PKHTestnet[0], 'testnet');
var b = new Address(a.toString());
b.toString().should.equal(PKHTestnet[0]);
b.network.should.equal('testnet');
b.network.should.equal(Networks.testnet);
});
it('should derive from this known address string livenet scripthash', function() {

View File

@ -1,9 +1,10 @@
'use strict';
var chai = chai || require('chai');
var should = chai.should();
var expect = chai.expect;
var bitcore = require('..');
var expect = chai.expect;
var Networks = bitcore.Networks;
var should = chai.should();
var URI = bitcore.URI;
describe('URI', function() {
@ -62,11 +63,11 @@ describe('URI', function() {
uri = new URI('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
uri.address.should.be.instanceof(bitcore.Address);
uri.network.should.equal('livenet');
uri.network.should.equal(Networks.livenet);
uri = new URI('bitcoin:mkYY5NRvikVBY1EPtaq9fAFgquesdjqECw');
uri.address.should.be.instanceof(bitcore.Address);
uri.network.should.equal('testnet');
uri.network.should.equal(Networks.testnet);
uri = new URI('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=1.2&other=param');
uri.address.should.be.instanceof(bitcore.Address);
@ -92,14 +93,13 @@ describe('URI', function() {
address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj'
});
uri.address.should.be.instanceof(bitcore.Address);
uri.network.should.equal('livenet');
uri.network.should.equal(Networks.livenet);
uri = new URI({
address: 'mkYY5NRvikVBY1EPtaq9fAFgquesdjqECw'
});
uri.address.should.be.instanceof(bitcore.Address);
uri.network.should.equal('testnet');
uri.network.should.equal(Networks.testnet);
uri = new URI({
address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',