Daniel Cousens
11 years ago
9 changed files with 158 additions and 187 deletions
@ -1,64 +1,27 @@ |
|||||
var base58 = require('./base58') |
var assert = require('assert') |
||||
var base58check = require('./base58check') |
var base58check = require('./base58check') |
||||
var convert = require('./convert') |
|
||||
var bitcoin = require('./network').bitcoin.pubKeyHash |
|
||||
|
|
||||
function Address(bytes, version) { |
function Address(hash, version) { |
||||
if (!(this instanceof Address)) { |
assert(Buffer.isBuffer(hash), 'First argument must be a Buffer') |
||||
return new Address(bytes, version) |
assert.strictEqual(hash.length, 20, 'Invalid hash length') |
||||
} |
assert.strictEqual(version & 0xFF, version, 'Invalid version byte') |
||||
|
|
||||
if (bytes instanceof Address) { |
this.hash = hash |
||||
this.hash = bytes.hash |
this.version = version |
||||
this.version = bytes.version |
|
||||
} |
|
||||
else if (typeof bytes === 'string') { |
|
||||
if (bytes.length <= 35) { |
|
||||
var decode = base58check.decode(bytes) |
|
||||
|
|
||||
this.hash = decode.payload |
|
||||
this.version = decode.version |
|
||||
} |
|
||||
else if (bytes.length <= 40) { |
|
||||
this.hash = convert.hexToBytes(bytes) |
|
||||
this.version = version || bitcoin |
|
||||
} |
|
||||
else { |
|
||||
throw new Error('Invalid or unrecognized input') |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
this.hash = bytes |
|
||||
this.version = version || bitcoin |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
/** |
// Import functions
|
||||
* Serialize this object as a standard Bitcoin address. |
Address.fromBase58Check = function(string) { |
||||
* Returns the address as a base58-encoded string in the standardized format. |
var decode = base58check.decode(string) |
||||
*/ |
|
||||
Address.prototype.toString = function () { |
|
||||
return base58check.encode(this.hash.slice(0), this.version) |
|
||||
} |
|
||||
|
|
||||
/** |
return new Address(decode.payload, decode.version) |
||||
* Returns the version of an address, e.g. if the address belongs to the main |
|
||||
* net or the test net. |
|
||||
*/ |
|
||||
Address.getVersion = function (address) { |
|
||||
return base58.decode(address)[0] |
|
||||
} |
} |
||||
|
Address.prototype.fromString = Address.prototype.fromBase58Check |
||||
|
|
||||
/** |
// Export functions
|
||||
* Returns true if a bitcoin address is a valid address, otherwise false. |
Address.prototype.toBase58Check = function () { |
||||
*/ |
return base58check.encode(this.hash, this.version) |
||||
Address.validate = function (address) { |
|
||||
try { |
|
||||
base58check.decode(address) |
|
||||
return true |
|
||||
} catch (e) { |
|
||||
return false |
|
||||
} |
|
||||
} |
} |
||||
|
Address.prototype.toString = Address.prototype.toBase58Check |
||||
|
|
||||
module.exports = Address |
module.exports = Address |
||||
|
@ -1,111 +1,49 @@ |
|||||
var assert = require('assert') |
var assert = require('assert') |
||||
var Address = require('../src/address') |
var Address = require('..').Address |
||||
var network = require('../src/network') |
var fixtures = require('./fixtures/address') |
||||
var base58 = require('../src/base58') |
|
||||
var base58check = require('../src/base58check') |
|
||||
var bitcoin = network.bitcoin.pubKeyHash |
|
||||
var testnet = network.testnet.pubKeyHash |
|
||||
|
|
||||
describe('Address', function() { |
describe('Address', function() { |
||||
var testnetAddress, bitcoinAddress |
var bothVectors = fixtures.pubKeyHash.concat(fixtures.scriptHash) |
||||
var testnetP2shAddress, bitcoinP2shAddress |
|
||||
|
|
||||
beforeEach(function(){ |
describe('Constructor', function() { |
||||
bitcoinAddress = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa' |
it('does not mutate the input', function() { |
||||
testnetAddress = 'mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhef' |
bothVectors.forEach(function(f) { |
||||
bitcoinP2shAddress = '3NJZLcZEEYBpxYEUGewU4knsQRn1WM5Fkt' |
var hash = new Buffer(f.hex, 'hex') |
||||
testnetP2shAddress = '2MxKEf2su6FGAUfCEAHreGFQvEYrfYNHvL7' |
var addr = new Address(hash, f.version) |
||||
}) |
|
||||
|
|
||||
describe('parsing', function() { |
|
||||
it('works with Address object', function() { |
|
||||
var addr = new Address(new Address('mwrB4fgT1KSBCqELaWv7o7tsExuQzW3NY3', network.testnet.pubKeyHash)) |
|
||||
|
|
||||
assert.equal(addr.toString(), 'mwrB4fgT1KSBCqELaWv7o7tsExuQzW3NY3') |
|
||||
assert.equal(addr.version, network.testnet.pubKeyHash) |
|
||||
}) |
|
||||
|
|
||||
it('works with hex', function() { |
|
||||
var addr = new Address('13483382d3c3d43fc9d7b52e652b6bbb70e8b667') |
|
||||
assert.equal(addr.toString(), '12kxLGqrnnchwN9bHHNV2fWDtJGwxKTcJS') |
|
||||
}) |
|
||||
|
|
||||
it('throws error for invalid or unrecognized input', function() { |
|
||||
assert.throws(function() { |
|
||||
new Address('beepboopbeepboopbeepboopbeepboopbeepboopbeep') |
|
||||
}, Error) |
|
||||
}) |
|
||||
|
|
||||
it('works for byte input', function() { |
|
||||
var hash = base58check.decode(bitcoinAddress) |
|
||||
var addr = new Address(hash.payload) |
|
||||
assert.equal(addr.hash, hash.payload) |
|
||||
assert.equal(network.bitcoin.pubKeyHash, hash.version) |
|
||||
|
|
||||
var hash = base58check.decode(testnetAddress) |
assert.equal(addr.version, f.version) |
||||
var addr = new Address(hash.payload) |
assert.equal(addr.hash.toString('hex'), f.hex) |
||||
assert.equal(addr.hash, hash.payload) |
}) |
||||
assert.equal(network.testnet.pubKeyHash, hash.version) |
|
||||
}) |
|
||||
|
|
||||
it('fails for bad input', function() { |
|
||||
assert.throws(function() { |
|
||||
new Address('foo') |
|
||||
}, Error) |
|
||||
}) |
}) |
||||
}) |
}) |
||||
|
|
||||
describe('getVersion', function() { |
describe('fromBase58Check', function() { |
||||
it('returns the proper address version', function() { |
it('throws on invalid base58check', function() { |
||||
assert.equal(Address.getVersion(bitcoinAddress), network.bitcoin.pubKeyHash) |
fixtures.malformed.forEach(function(f) { |
||||
assert.equal(Address.getVersion(testnetAddress), network.testnet.pubKeyHash) |
assert.throws(function() { |
||||
|
Address.fromBase58Check(f.base58check) |
||||
|
}) |
||||
|
}) |
||||
}) |
}) |
||||
}) |
|
||||
|
|
||||
describe('toString', function() { |
bothVectors.forEach(function(f) { |
||||
it('defaults to base58', function() { |
it('imports ' + f.description + ' correctly', function() { |
||||
var addr = '18fN1QTGWmHWCA9r2dyDH6FbMEyc7XHmQQ' |
var addr = Address.fromBase58Check(f.base58check) |
||||
assert.equal((new Address(addr)).toString(), addr) |
|
||||
}) |
|
||||
}) |
|
||||
|
|
||||
describe('Constructor', function(){ |
assert.equal(addr.version, f.version) |
||||
it('resolves version correctly', function(){ |
assert.equal(addr.hash.toString('hex'), f.hex) |
||||
assert.equal((new Address(testnetAddress)).version, testnet) |
}) |
||||
assert.equal((new Address(bitcoinAddress)).version, bitcoin) |
|
||||
assert.equal((new Address(testnetP2shAddress)).version, network.testnet.scriptHash) |
|
||||
assert.equal((new Address(bitcoinP2shAddress)).version, network.bitcoin.scriptHash) |
|
||||
}) |
}) |
||||
}) |
}) |
||||
|
|
||||
describe('validate', function() { |
describe('toBase58Check', function() { |
||||
it('validates known good addresses', function() { |
bothVectors.forEach(function(f) { |
||||
function validate(addr, expectedVersion) { |
it('exports ' + f.description + ' correctly', function() { |
||||
assert.ok(Address.validate(addr)) |
var addr = Address.fromBase58Check(f.base58check) |
||||
} |
var result = addr.toBase58Check() |
||||
|
|
||||
validate(testnetAddress) |
|
||||
validate(bitcoinAddress) |
|
||||
validate('12KYrjTdVGjFMtaxERSk3gphreJ5US8aUP') |
|
||||
validate('12QeMLzSrB8XH8FvEzPMVoRxVAzTr5XM2y') |
|
||||
validate('1oNLrsHnBcR6dpaBpwz3LSwutbUNkNSjs') |
|
||||
validate('1SQHtwR5oJRKLfiWQ2APsAd9miUc4k2ez') |
|
||||
validate('116CGDLddrZhMrTwhCVJXtXQpxygTT1kHd') |
|
||||
|
|
||||
// p2sh addresses
|
|
||||
validate(testnetP2shAddress) |
|
||||
validate(bitcoinP2shAddress) |
|
||||
}) |
|
||||
|
|
||||
it('does not validate illegal examples', function() { |
|
||||
function invalid(addr) { |
|
||||
assert.ok(!Address.validate(addr)) |
|
||||
} |
|
||||
|
|
||||
invalid(''); //empty should be invalid
|
assert.equal(result, f.base58check) |
||||
invalid('%%@'); // invalid base58 string
|
}) |
||||
invalid('1A1zP1eP5QGefi2DzPTf2L5SLmv7DivfNz'); // bad address (doesn't checksum)
|
|
||||
invalid('mzBc4XEFSdzCDcTxAgf6EZXgsZWpztRhe'); // bad address (doesn't checksum)
|
|
||||
}) |
}) |
||||
}) |
}) |
||||
}) |
}) |
||||
|
@ -0,0 +1,42 @@ |
|||||
|
module.exports = { |
||||
|
pubKeyHash: [ |
||||
|
{ |
||||
|
description: 'pubKeyHash (bitcoin)', |
||||
|
version: 0, |
||||
|
hex: '751e76e8199196d454941c45d1b3a323f1433bd6', |
||||
|
base58check: '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH' |
||||
|
}, |
||||
|
{ |
||||
|
description: 'pubKeyHash (testnet)', |
||||
|
version: 111, |
||||
|
hex: '751e76e8199196d454941c45d1b3a323f1433bd6', |
||||
|
base58check: 'mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r' |
||||
|
} |
||||
|
], |
||||
|
scriptHash: [ |
||||
|
{ |
||||
|
description: 'scriptHash (bitcoin)', |
||||
|
version: 5, |
||||
|
hex: 'cd7b44d0b03f2d026d1e586d7ae18903b0d385f6', |
||||
|
base58check: '3LRW7jeCvQCRdPF8S3yUCfRAx4eqXFmdcr' |
||||
|
}, |
||||
|
{ |
||||
|
description: 'scriptHash (testnet)', |
||||
|
version: 196, |
||||
|
hex: 'cd7b44d0b03f2d026d1e586d7ae18903b0d385f6', |
||||
|
base58check: '2NByiBUaEXrhmqAsg7BbLpcQSAQs1EDwt5w' |
||||
|
} |
||||
|
], |
||||
|
malformed: [ |
||||
|
'45k2PvUfZw', |
||||
|
'8cVHMKGRJGMEVz', |
||||
|
'AMPCMAGBmj9EE9oGED', |
||||
|
'oJPsqvHTSFFWMcmNS3aDidZexw', |
||||
|
'bpiuHmqwCdiHx4ASNLGvZeBw9taY', |
||||
|
'2ansc1MsREU2HetNdPGs2eHXTY16ircdyaH', |
||||
|
'iTKsHH39ooQPFxzX6RFtjPESpQ1', |
||||
|
'4TU74v3jnoTZGV5UuJGcr7XRg7hU', |
||||
|
'2a3wk37F1YmfqVtBam4gEn63oNuj', |
||||
|
'3rtH2aquyk4q1KGaXuiMGxaGfVPH' |
||||
|
] |
||||
|
} |
Loading…
Reference in new issue