Address: add Address.*ScriptPubKey and tests
The introduction of these two functions allow for the all the network related code to be eventually removed from Transaction and Script. Previously the result for non-standard transactions was undefined behaviour. This change mandates that an exception is thrown if a non-standard transaction is input.
This commit is contained in:
parent
0822def7e0
commit
5e0d38ba54
4 changed files with 129 additions and 30 deletions
|
@ -1,5 +1,22 @@
|
|||
var assert = require('assert')
|
||||
var base58check = require('./base58check')
|
||||
var networks = require('./networks')
|
||||
|
||||
function findScriptTypeByVersion(queryVersion) {
|
||||
for (var networkName in networks) {
|
||||
var network = networks[networkName]
|
||||
|
||||
for (var versionName in network) {
|
||||
var version = network[versionName]
|
||||
|
||||
if (version === queryVersion) {
|
||||
return versionName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Version has no corresponding network')
|
||||
}
|
||||
|
||||
function Address(hash, version) {
|
||||
assert(Buffer.isBuffer(hash), 'First argument must be a Buffer')
|
||||
|
@ -17,10 +34,48 @@ Address.fromBase58Check = function(string) {
|
|||
return new Address(decode.payload, decode.version)
|
||||
}
|
||||
|
||||
Address.fromScriptPubKey = function(script, network) {
|
||||
network = network || networks.bitcoin
|
||||
|
||||
var type = script.getOutType()
|
||||
|
||||
// Pay-to-pubKeyHash
|
||||
if (type === 'pubkeyhash') {
|
||||
return new Address(new Buffer(script.chunks[2]), network.pubKeyHash)
|
||||
}
|
||||
|
||||
// Pay-to-scriptHash
|
||||
else if (type === 'scripthash') {
|
||||
return new Address(new Buffer(script.chunks[1]), network.scriptHash)
|
||||
}
|
||||
|
||||
throw new Error('Could not derive address from script')
|
||||
}
|
||||
|
||||
// Export functions
|
||||
Address.prototype.toBase58Check = function () {
|
||||
return base58check.encode(this.hash, this.version)
|
||||
}
|
||||
|
||||
Address.prototype.toScriptPubKey = function() {
|
||||
var scriptType = findScriptTypeByVersion(this.version)
|
||||
|
||||
// Pay-to-pubKeyHash
|
||||
if (scriptType === 'pubKeyHash') {
|
||||
return Script.createPubKeyHashScriptPubKey(this.hash)
|
||||
}
|
||||
|
||||
// Pay-to-scriptHash
|
||||
else if (scriptType === 'scriptHash') {
|
||||
return Script.createP2SHScriptPubKey(this.hash)
|
||||
}
|
||||
|
||||
throw new Error('Address has no matching script')
|
||||
}
|
||||
|
||||
Address.prototype.toString = Address.prototype.toBase58Check
|
||||
|
||||
module.exports = Address
|
||||
|
||||
// http://stackoverflow.com/a/14098262
|
||||
var Script = require('./script')
|
||||
|
|
|
@ -205,13 +205,7 @@ Script.prototype.toScriptHash = function() {
|
|||
Script.prototype.getToAddress = function(network) {
|
||||
network = network || networks.bitcoin
|
||||
|
||||
if(isPubkeyhash.call(this)) {
|
||||
return new Address(new Buffer(this.chunks[2]), network.pubKeyHash)
|
||||
}
|
||||
|
||||
assert(isScripthash.call(this))
|
||||
|
||||
return new Address(new Buffer(this.chunks[1]), network.scriptHash)
|
||||
return Address.fromScriptPubKey(this, network)
|
||||
}
|
||||
|
||||
Script.prototype.getFromAddress = function(version) {
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
var assert = require('assert')
|
||||
var Address = require('..').Address
|
||||
var networks = require('..').networks
|
||||
var Script = require('..').Script
|
||||
|
||||
var b58fixtures = require('./fixtures/base58')
|
||||
var fixtures = require('./fixtures/address')
|
||||
|
||||
describe('Address', function() {
|
||||
var bothVectors = fixtures.pubKeyHash.concat(fixtures.scriptHash)
|
||||
function h2b(h) { return new Buffer(h, 'hex') }
|
||||
|
||||
describe('Address', function() {
|
||||
describe('Constructor', function() {
|
||||
it('does not mutate the input', function() {
|
||||
bothVectors.forEach(function(f) {
|
||||
fixtures.valid.forEach(function(f) {
|
||||
var hash = new Buffer(f.hex, 'hex')
|
||||
var addr = new Address(hash, f.version)
|
||||
|
||||
|
@ -28,8 +30,8 @@ describe('Address', function() {
|
|||
})
|
||||
})
|
||||
|
||||
bothVectors.forEach(function(f) {
|
||||
it('imports ' + f.description + ' correctly', function() {
|
||||
fixtures.valid.forEach(function(f) {
|
||||
it('imports ' + f.description + '(' + f.network + ') correctly', function() {
|
||||
var addr = Address.fromBase58Check(f.base58check)
|
||||
|
||||
assert.equal(addr.version, f.version)
|
||||
|
@ -38,9 +40,21 @@ describe('Address', function() {
|
|||
})
|
||||
})
|
||||
|
||||
describe('fromScriptPubKey', function() {
|
||||
fixtures.valid.forEach(function(f) {
|
||||
it('imports ' + f.description + '(' + f.network + ') correctly', function() {
|
||||
var script = Script.fromHex(f.script)
|
||||
var addr = Address.fromScriptPubKey(script, networks[f.network])
|
||||
|
||||
assert.equal(addr.version, f.version)
|
||||
assert.equal(addr.hash.toString('hex'), f.hex)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('toBase58Check', function() {
|
||||
bothVectors.forEach(function(f) {
|
||||
it('exports ' + f.description + ' correctly', function() {
|
||||
fixtures.valid.forEach(function(f) {
|
||||
it('exports ' + f.description + '(' + f.network + ') correctly', function() {
|
||||
var addr = Address.fromBase58Check(f.base58check)
|
||||
var result = addr.toBase58Check()
|
||||
|
||||
|
@ -48,4 +62,25 @@ describe('Address', function() {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('toScriptPubKey', function() {
|
||||
fixtures.valid.forEach(function(f) {
|
||||
it('imports ' + f.description + '(' + f.network + ') correctly', function() {
|
||||
var addr = Address.fromBase58Check(f.base58check)
|
||||
var script = addr.toScriptPubKey()
|
||||
|
||||
assert.equal(script.toHex(), f.script)
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.toScriptPubKey.forEach(function(f) {
|
||||
it('throws on ' + f.description, function() {
|
||||
var addr = new Address(h2b(f.hex), f.version)
|
||||
|
||||
assert.throws(function() {
|
||||
addr.toScriptPubKey()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
45
test/fixtures/address.js
vendored
45
test/fixtures/address.js
vendored
|
@ -1,30 +1,45 @@
|
|||
module.exports = {
|
||||
pubKeyHash: [
|
||||
valid: [
|
||||
{
|
||||
description: 'pubKeyHash (bitcoin)',
|
||||
description: 'pubKeyHash',
|
||||
network: 'bitcoin',
|
||||
version: 0,
|
||||
hex: '751e76e8199196d454941c45d1b3a323f1433bd6',
|
||||
base58check: '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH'
|
||||
base58check: '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH',
|
||||
script: '76a914751e76e8199196d454941c45d1b3a323f1433bd688ac'
|
||||
},
|
||||
{
|
||||
description: 'pubKeyHash (testnet)',
|
||||
description: 'pubKeyHash',
|
||||
network: 'testnet',
|
||||
version: 111,
|
||||
hex: '751e76e8199196d454941c45d1b3a323f1433bd6',
|
||||
base58check: 'mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r'
|
||||
}
|
||||
],
|
||||
scriptHash: [
|
||||
{
|
||||
description: 'scriptHash (bitcoin)',
|
||||
version: 5,
|
||||
hex: 'cd7b44d0b03f2d026d1e586d7ae18903b0d385f6',
|
||||
base58check: '3LRW7jeCvQCRdPF8S3yUCfRAx4eqXFmdcr'
|
||||
base58check: 'mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r',
|
||||
script: '76a914751e76e8199196d454941c45d1b3a323f1433bd688ac'
|
||||
},
|
||||
{
|
||||
description: 'scriptHash (testnet)',
|
||||
description: 'scriptHash',
|
||||
network: 'bitcoin',
|
||||
version: 5,
|
||||
hex: 'cd7b44d0b03f2d026d1e586d7ae18903b0d385f6',
|
||||
base58check: '3LRW7jeCvQCRdPF8S3yUCfRAx4eqXFmdcr',
|
||||
script: 'a914cd7b44d0b03f2d026d1e586d7ae18903b0d385f687'
|
||||
},
|
||||
{
|
||||
description: 'scriptHash',
|
||||
network: 'testnet',
|
||||
version: 196,
|
||||
hex: 'cd7b44d0b03f2d026d1e586d7ae18903b0d385f6',
|
||||
base58check: '2NByiBUaEXrhmqAsg7BbLpcQSAQs1EDwt5w'
|
||||
base58check: '2NByiBUaEXrhmqAsg7BbLpcQSAQs1EDwt5w',
|
||||
script: 'a914cd7b44d0b03f2d026d1e586d7ae18903b0d385f687'
|
||||
}
|
||||
],
|
||||
invalid: {
|
||||
toScriptPubKey: [
|
||||
{
|
||||
description: 'Unknown Address version',
|
||||
version: 0x99,
|
||||
hex: 'cd7b44d0b03f2d026d1e586d7ae18903b0d385f6'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue