From 13d978fd40f718693d3e67b6fe9acf71dba75cc6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 22 Oct 2014 17:42:34 +1100 Subject: [PATCH] Address: consistent namespacing and decode/encode functionality --- src/address.js | 71 +++++++++++++++++++++++--------------- src/ecpair.js | 7 ++-- src/transaction.js | 6 ++-- test/address.js | 38 +++++++++++++++----- test/fixtures/address.json | 18 +++++++--- test/fixtures/crypto.json | 2 +- 6 files changed, 93 insertions(+), 49 deletions(-) diff --git a/src/address.js b/src/address.js index fbb854c1b..3f4666473 100644 --- a/src/address.js +++ b/src/address.js @@ -3,25 +3,7 @@ var base58check = require('bs58check') var networks = require('./networks') var scripts = require('./scripts') -function fromOutputScript(script, network) { - network = network || networks.bitcoin - - var type = scripts.classifyOutput(script) - var version - var hash - - if (type === 'pubkeyhash') { - version = network.pubKeyHash - hash = script.chunks[2] - - } else if (type === 'scripthash') { - version = network.scriptHash - hash = script.chunks[1] - - } else { - assert(false, type + ' has no matching Address') - } - +function encode(version, hash) { var payload = new Buffer(21) payload.writeUInt8(version, 0) hash.copy(payload, 1) @@ -29,26 +11,61 @@ function fromOutputScript(script, network) { return base58check.encode(payload) } -function toOutputScript(address) { +function decode(address) { var payload = base58check.decode(address) var version = payload.readUInt8(0) - var hash = payload.slice(1) + var network for (var networkName in networks) { - var network = networks[networkName] + var network2 = networks[networkName] - if (version === network.pubKeyHash) { - return scripts.pubKeyHashOutput(hash) - - } else if (version === network.scriptHash) { - return scripts.scriptHashOutput(hash) + if (version === network2.pubKeyHash || version === network2.scriptHash) { + network = network2 + break } } + return { + hash: payload.slice(1), + network: network, + version: version + } +} + +function fromOutputScript(script, network) { + network = network || networks.bitcoin + + var type = scripts.classifyOutput(script) + + switch (type) { + case 'pubkeyhash': + return encode(network.pubKeyHash, script.chunks[2]) + + case 'scripthash': + return encode(network.scriptHash, script.chunks[1]) + } + + assert(false, type + ' has no matching Address') +} + +function toOutputScript(address) { + var decoded = decode(address) + var network = decoded.network || {} + + switch (decoded.version) { + case network.pubKeyHash: + return scripts.pubKeyHashOutput(decoded.hash) + + case network.scriptHash: + return scripts.scriptHashOutput(decoded.hash) + } + assert(false, address + ' has no matching Script') } module.exports = { + decode: decode, + encode: encode, fromOutputScript: fromOutputScript, toOutputScript: toOutputScript } diff --git a/src/ecpair.js b/src/ecpair.js index 7e64d1425..16ad50f1c 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -1,3 +1,4 @@ +var address = require('./address') var assert = require('assert') var base58check = require('bs58check') var bcrypto = require('./crypto') @@ -122,11 +123,7 @@ ECPair.prototype.getAddress = function() { var hash = bcrypto.hash160(pubKey) var version = this.network.pubKeyHash - var payload = new Buffer(21) - payload.writeUInt8(version, 0) - hash.copy(payload, 1) - - return base58check.encode(payload) + return address.encode(version, hash) } ECPair.prototype.getPublicKeyBuffer = function() { diff --git a/src/transaction.js b/src/transaction.js index 1048021dd..85c090c00 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -1,7 +1,7 @@ +var address = require('./address') var assert = require('assert') var scripts = require('./scripts') -var Address = require('./address') var ECPair = require('./ecpair') var ECSignature = require('./ecsignature') var RawTransaction = require('./raw_transaction') @@ -152,7 +152,7 @@ Transaction.prototype.addOutput = function(scriptPubKey, value) { // Attempt to get a valid script if it's a base58 address if (typeof scriptPubKey === 'string') { - scriptPubKey = Address.toOutputScript(scriptPubKey) + scriptPubKey = address.toOutputScript(scriptPubKey) } return this.tx.addOutput(scriptPubKey, value) @@ -241,7 +241,7 @@ Transaction.prototype.sign = function(index, keyPair, redeemScript, hashType) { hash = this.tx.hashForSignature(index, redeemScript, hashType) } else { - prevOutScript = prevOutScript || Address.toOutputScript(keyPair.getAddress()) + prevOutScript = prevOutScript || address.toOutputScript(keyPair.getAddress()) prevOutType = prevOutType || 'pubkeyhash' assert.notEqual(prevOutType, 'scripthash', 'PrevOutScript is P2SH, missing redeemScript') diff --git a/test/address.js b/test/address.js index 241bed3f5..a0253d0ec 100644 --- a/test/address.js +++ b/test/address.js @@ -1,17 +1,39 @@ var assert = require('assert') var networks = require('../src/networks') -var Address = require('../src/address') +var address = require('../src/address') var Script = require('../src/script') var fixtures = require('./fixtures/address.json') -describe('Address', function() { +describe('address', function() { + describe('decode', function() { + fixtures.valid.forEach(function(f) { + it('decodes ' + f.address + ' correctly', function() { + var decoded = address.decode(f.address) + + assert.equal(decoded.version, f.version) + assert.equal(decoded.hash.toString('hex'), f.hash) + assert.equal(decoded.network, networks[f.network]) + }) + }) + }) + + describe('encode', function() { + fixtures.valid.forEach(function(f) { + it('encoded ' + f.address + ' correctly', function() { + var result = address.encode(f.version, new Buffer(f.hash, 'hex')) + + assert.equal(result, f.address) + }) + }) + }) + describe('fromOutputScript', function() { fixtures.valid.forEach(function(f) { - it('imports ' + f.description + '(' + f.network + ') correctly', function() { + it('transforms ' + f.script + ' (' + f.network + ') to ' + f.address, function() { var script = Script.fromHex(f.script) - var addr = Address.fromOutputScript(script, networks[f.network]) + var addr = address.fromOutputScript(script, networks[f.network]) assert.equal(addr, f.address) }) @@ -22,7 +44,7 @@ describe('Address', function() { var script = Script.fromHex(f.hex) assert.throws(function() { - Address.fromOutputScript(script) + address.fromOutputScript(script) }, new RegExp(f.description)) }) }) @@ -30,8 +52,8 @@ describe('Address', function() { describe('toOutputScript', function() { fixtures.valid.forEach(function(f) { - it('imports ' + f.description + '(' + f.network + ') correctly', function() { - var script = Address.toOutputScript(f.address) + it('transforms ' + f.address + ' to ' + f.script, function() { + var script = address.toOutputScript(f.address) assert.equal(script.toHex(), f.script) }) @@ -40,7 +62,7 @@ describe('Address', function() { fixtures.invalid.toOutputScript.forEach(function(f) { it('throws when ' + f.description, function() { assert.throws(function() { - Address.toOutputScript(f.address) + address.toOutputScript(f.address) }, new RegExp(f.description)) }) }) diff --git a/test/fixtures/address.json b/test/fixtures/address.json index 600e94583..e08093b4f 100644 --- a/test/fixtures/address.json +++ b/test/fixtures/address.json @@ -4,25 +4,33 @@ "description": "pubKeyHash", "network": "bitcoin", "address": "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH", - "script": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac" + "script": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac", + "version": 0, + "hash": "751e76e8199196d454941c45d1b3a323f1433bd6" }, { "description": "scriptHash", "network": "bitcoin", "address": "3LRW7jeCvQCRdPF8S3yUCfRAx4eqXFmdcr", - "script": "a914cd7b44d0b03f2d026d1e586d7ae18903b0d385f687" + "script": "a914cd7b44d0b03f2d026d1e586d7ae18903b0d385f687", + "version": 5, + "hash": "cd7b44d0b03f2d026d1e586d7ae18903b0d385f6" }, { "description": "pubKeyHash", "network": "testnet", "address": "mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r", - "script": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac" + "script": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac", + "version": 111, + "hash": "751e76e8199196d454941c45d1b3a323f1433bd6" }, { "description": "scriptHash", "network": "testnet", "address": "2NByiBUaEXrhmqAsg7BbLpcQSAQs1EDwt5w", - "script": "a914cd7b44d0b03f2d026d1e586d7ae18903b0d385f687" + "script": "a914cd7b44d0b03f2d026d1e586d7ae18903b0d385f687", + "version": 196, + "hash": "cd7b44d0b03f2d026d1e586d7ae18903b0d385f6" } ], "invalid": { @@ -47,4 +55,4 @@ } ] } -} +} \ No newline at end of file diff --git a/test/fixtures/crypto.json b/test/fixtures/crypto.json index aa66fec1c..4f48d3df0 100644 --- a/test/fixtures/crypto.json +++ b/test/fixtures/crypto.json @@ -33,4 +33,4 @@ "sha256": "a7fb8276035057ed6479c5f2305a96da100ac43f0ac10f277e5ab8c5457429da" } ] -} \ No newline at end of file +}