Replace ScriptToAddress with ScriptToAddrHash to return an address hash.

This commit is contained in:
Josh Rickmar 2013-10-08 10:49:45 -04:00
parent 52a1488eaf
commit 83a19b239d
3 changed files with 60 additions and 68 deletions

View file

@ -4,11 +4,6 @@
package btcscript
import (
"github.com/conformal/btcutil"
"github.com/conformal/btcwire"
)
// ScriptType is an enum type that represents the type of a script. It is
// returned from ScriptToAddress as part of the metadata about the script.
// It implements the Stringer interface for nice printing.
@ -62,8 +57,8 @@ const (
scrNoAddr
)
// ScriptToAddress extracts a payment address and the type out of a PkScript
func ScriptToAddress(script []byte) (ScriptType, string, error) {
// ScriptToAddrHash extracts a 20-byte public key hash and the type out of a PkScript
func ScriptToAddrHash(script []byte) (ScriptType, []byte, error) {
// Currently this only understands one form of PkScript
validformats := []pkformat{
{ScriptAddr, scrPayAddr, 25, []pkbytes{{0, OP_DUP}, {1, OP_HASH160}, {2, OP_DATA_20}, {23, OP_EQUALVERIFY}, {24, OP_CHECKSIG}}, true},
@ -91,10 +86,10 @@ func ScriptToAddress(script []byte) (ScriptType, string, error) {
{ScriptStrange, scrNoAddr, 33, []pkbytes{{0, OP_DATA_32}}, false},
{ScriptStrange, scrNoAddr, 33, []pkbytes{{0, OP_HASH160}, {1, OP_DATA_20}, {22, OP_EQUAL}}, false},
}
return scriptToAddressTemplate(script, validformats)
return scriptToAddrHashTemplate(script, validformats)
}
func scriptToAddressTemplate(script []byte, validformats []pkformat) (ScriptType, string, error) {
func scriptToAddrHashTemplate(script []byte, validformats []pkformat) (ScriptType, []byte, error) {
var format pkformat
var success bool
for _, format = range validformats {
@ -109,7 +104,7 @@ func scriptToAddressTemplate(script []byte, validformats []pkformat) (ScriptType
success = true
for _, pkbyte := range format.databytes {
if pkbyte.off >= len(script) {
return ScriptUnknown, "Unknown",
return ScriptUnknown, nil,
StackErrInvalidAddrOffset
}
if script[pkbyte.off] != pkbyte.val {
@ -129,64 +124,50 @@ func scriptToAddressTemplate(script []byte, validformats []pkformat) (ScriptType
if len(script) > 1 {
// check for a few special case
if script[len(script)-1] == OP_CHECK_MULTISIG {
return ScriptStrange, "Unknown", nil
return ScriptStrange, nil, nil
}
if script[0] == OP_0 && (len(script) <= 75 && byte(len(script)) == script[1]+2) {
return ScriptStrange, "Unknown", nil
return ScriptStrange, nil, nil
}
if script[0] == OP_HASH160 && len(script) == 23 && script[22] == OP_EQUAL {
return ScriptStrange, "Unknown", nil
return ScriptStrange, nil, nil
}
if script[0] == OP_DATA_36 && len(script) == 37 {
// Multisig ScriptSig
return ScriptStrange, "Unknown", nil
return ScriptStrange, nil, nil
}
}
return ScriptUnknown, "Unknown", StackErrUnknownAddress
return ScriptUnknown, nil, StackErrUnknownAddress
}
var atype byte
var abuf []byte
var addr string
var addrhash []byte
switch format.parsetype {
case scrPayAddr:
atype = 0x00
abuf = script[3:23]
addrhash = script[3:23]
case scrCollectAddr:
// script is replaced with the md160 of the pubkey
slen := len(script)
pubkey := script[slen-65:]
abuf = calcHash160(pubkey)
addrhash = calcHash160(pubkey)
case scrCollectAddrComp:
// script is replaced with the md160 of the pubkey
slen := len(script)
pubkey := script[slen-33:]
abuf = calcHash160(pubkey)
addrhash = calcHash160(pubkey)
case scrGeneratePubkeyAddr:
atype = 0x00
addr = "Unknown"
// unable to determine address hash from script
case scrNoAddr:
addr = "Unknown"
// unable to determine address hash from script
case scrPubkeyAddr:
atype = 0x00
pubkey := script[1:66]
abuf = calcHash160(pubkey)
addrhash = calcHash160(pubkey)
case scrPubkeyAddrComp:
atype = 0x00
pubkey := script[1:34]
abuf = calcHash160(pubkey)
addrhash = calcHash160(pubkey)
default:
return ScriptUnknown, "Unknown", StackErrInvalidParseType
return ScriptUnknown, nil, StackErrInvalidParseType
}
if abuf != nil {
addrbytes := append([]byte{atype}, abuf[:]...)
cksum := btcwire.DoubleSha256(addrbytes)
addrbytes = append(addrbytes, cksum[:4]...)
addr = btcutil.Base58Encode(addrbytes)
}
return format.addrtype, addr, nil
return format.addrtype, addrhash, nil
}

View file

@ -4,13 +4,14 @@
package btcscript_test
import (
"bytes"
"github.com/conformal/btcscript"
"testing"
)
type addressTest struct {
script []byte
address string
addrhash []byte
shouldFail error
class btcscript.ScriptType
}
@ -26,8 +27,10 @@ var addressTests = []addressTest{
0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f,
0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12,
0xa3, btcscript.OP_CHECKSIG},
address: "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S",
class: btcscript.ScriptPubKey,
addrhash: []byte{0x11, 0xb3, 0x66, 0xed, 0xfc, 0x0a,
0x8b, 0x66, 0xfe, 0xeb, 0xae, 0x5c, 0x2e,
0x25, 0xa7, 0xb6, 0xa5, 0xd1, 0xcf, 0x31},
class: btcscript.ScriptPubKey,
},
{script: []byte{btcscript.OP_DATA_65,
0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
@ -51,8 +54,8 @@ var addressTests = []addressTest{
0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c,
0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22,
0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01},
address: "Unknown",
class: btcscript.ScriptPubKey,
addrhash: nil,
class: btcscript.ScriptPubKey,
},
{script: []byte{btcscript.OP_DUP, btcscript.OP_HASH160,
btcscript.OP_DATA_20,
@ -61,8 +64,10 @@ var addressTests = []addressTest{
0x09, 0xa3, 0x05, 0x64,
btcscript.OP_EQUALVERIFY, btcscript.OP_CHECKSIG,
},
address: "1Gmt8AzabtngttF3PcZzLR1p7uCMaHNuGY",
class: btcscript.ScriptAddr,
addrhash: []byte{0xad, 0x06, 0xdd, 0x6d, 0xde, 0xe5,
0x5c, 0xbc, 0xa9, 0xa9, 0xe3, 0x71, 0x3b,
0xd7, 0x58, 0x75, 0x09, 0xa3, 0x05, 0x64},
class: btcscript.ScriptAddr,
},
{script: []byte{btcscript.OP_DATA_73,
0x30, 0x46, 0x02, 0x21, 0x00, 0xdd, 0xc6, 0x97,
@ -85,8 +90,10 @@ var addressTests = []addressTest{
0x93, 0x7d, 0x58, 0xe5, 0xa7, 0x5a, 0x71, 0x04,
0x2d, 0x40, 0x38, 0x8a, 0x4d, 0x30, 0x7f, 0x88,
0x7d},
address: "16tRBxwU7t5hEHaPLqiE35gS3jaGBppraH",
class: btcscript.ScriptAddr,
addrhash: []byte{0x40, 0x92, 0x08, 0xf3, 0x87, 0xf4,
0x7f, 0xd2, 0x3a, 0x9f, 0x44, 0x5e, 0x14,
0xdc, 0x1f, 0x99, 0xbb, 0xb8, 0x0d, 0xaa},
class: btcscript.ScriptAddr,
},
{script: []byte{btcscript.OP_DATA_73,
0x30, 0x46, 0x02, 0x21, 0x00, 0xac, 0x7e, 0x4e,
@ -106,8 +113,10 @@ var addressTests = []addressTest{
0x72, 0x3d, 0x5a, 0xd4, 0x06, 0x8d, 0xdd, 0x30,
0x36,
},
address: "1272555ceTPn2WepjzVgFESWdfNQjqdjgp",
class: btcscript.ScriptAddr,
addrhash: []byte{0x0c, 0x1b, 0x83, 0xd0, 0x1d, 0x0f,
0xfb, 0x2b, 0xcc, 0xae, 0x60, 0x69, 0x63,
0x37, 0x6c, 0xca, 0x38, 0x63, 0xa7, 0xce},
class: btcscript.ScriptAddr,
},
{script: []byte{btcscript.OP_DATA_32,
0x30, 0x46, 0x02, 0x21, 0x00, 0xac, 0x7e, 0x4e,
@ -115,8 +124,8 @@ var addressTests = []addressTest{
0x87, 0x2a, 0xb9, 0xd3, 0x2c, 0xdc, 0x08, 0x33,
0x80, 0x73, 0x3e, 0x3e, 0x98, 0x47, 0xff, 0x77,
},
address: "Unknown",
class: btcscript.ScriptStrange,
addrhash: nil,
class: btcscript.ScriptStrange,
},
{script: []byte{btcscript.OP_DATA_33,
0x02, 0x40, 0x05, 0xc9, 0x45, 0xd8, 0x6a, 0xc6,
@ -126,8 +135,10 @@ var addressTests = []addressTest{
0x36,
btcscript.OP_CHECKSIG,
},
address: "1272555ceTPn2WepjzVgFESWdfNQjqdjgp",
class: btcscript.ScriptPubKey,
addrhash: []byte{0x0c, 0x1b, 0x83, 0xd0, 0x1d, 0x0f,
0xfb, 0x2b, 0xcc, 0xae, 0x60, 0x69, 0x63,
0x37, 0x6c, 0xca, 0x38, 0x63, 0xa7, 0xce},
class: btcscript.ScriptPubKey,
},
{script: []byte{btcscript.OP_DATA_33,
0x02, 0x40, 0x05, 0xc9, 0x45, 0xd8, 0x6a, 0xc6,
@ -137,8 +148,8 @@ var addressTests = []addressTest{
0x36,
btcscript.OP_CHECK_MULTISIG, // note this isn't a real tx
},
address: "Unknown",
class: btcscript.ScriptStrange,
addrhash: nil,
class: btcscript.ScriptStrange,
},
{script: []byte{btcscript.OP_0, btcscript.OP_DATA_33,
0x02, 0x40, 0x05, 0xc9, 0x45, 0xd8, 0x6a, 0xc6,
@ -147,8 +158,8 @@ var addressTests = []addressTest{
0x72, 0x3d, 0x5a, 0xd4, 0x06, 0x8d, 0xdd, 0x30,
0x36, // note this isn't a real tx
},
address: "Unknown",
class: btcscript.ScriptStrange,
addrhash: nil,
class: btcscript.ScriptStrange,
},
{script: []byte{btcscript.OP_HASH160, btcscript.OP_DATA_20,
0x02, 0x40, 0x05, 0xc9, 0x45, 0xd8, 0x6a, 0xc6,
@ -156,8 +167,8 @@ var addressTests = []addressTest{
0xa7, 0xa8, 0x45, 0xbd,
btcscript.OP_EQUAL, // note this isn't a real tx
},
address: "Unknown",
class: btcscript.ScriptStrange,
addrhash: nil,
class: btcscript.ScriptStrange,
},
{script: []byte{btcscript.OP_DATA_36,
0x02, 0x40, 0x05, 0xc9, 0x45, 0xd8, 0x6a, 0xc6,
@ -167,8 +178,8 @@ var addressTests = []addressTest{
0xa7, 0xa8, 0x45, 0xbd,
// note this isn't a real tx
},
address: "Unknown",
class: btcscript.ScriptStrange,
addrhash: nil,
class: btcscript.ScriptStrange,
},
{script: []byte{},
shouldFail: btcscript.StackErrUnknownAddress,
@ -177,7 +188,7 @@ var addressTests = []addressTest{
func TestAddresses(t *testing.T) {
for i, s := range addressTests {
class, address, err := btcscript.ScriptToAddress(s.script)
class, addrhash, err := btcscript.ScriptToAddrHash(s.script)
if s.shouldFail != nil {
if err != s.shouldFail {
t.Errorf("Address test %v failed is err [%v] should be [%v]", i, err, s.shouldFail)
@ -186,8 +197,8 @@ func TestAddresses(t *testing.T) {
if err != nil {
t.Errorf("Address test %v failed err %v", i, err)
} else {
if s.address != address {
t.Errorf("Address test %v mismatch is [%v] want [%v]", i, address, s.address)
if !bytes.Equal(s.addrhash, addrhash) {
t.Errorf("Address test %v mismatch is [%v] want [%v]", i, addrhash, s.addrhash)
}
if s.class != class {
t.Errorf("Address test %v class mismatch is [%v] want [%v]", i, class, s.class)

View file

@ -49,8 +49,8 @@ func TstSignatureScriptCustomReader(reader io.Reader, tx *btcwire.MsgTx, idx int
hashType, privkey, compress)
}
// Tests for internal error cases in ScriptToAddress.
// We pass bad format definitions to ScriptToAddrss to make sure the internal
// Tests for internal error cases in ScriptToAddrHash.
// We pass bad format definitions to ScriptToAddrHash to make sure the internal
// checks work correctly. This is located in internal_test.go and not address.go
// because of the ridiculous amount of internal types/constants that would
// otherwise need to be exported here.
@ -94,7 +94,7 @@ var TstPkFormats = []pkformatTest{
func TestBadPkFormat(t *testing.T) {
for _, test := range TstPkFormats {
ty, addr, err := scriptToAddressTemplate(test.script,
ty, addr, err := scriptToAddrHashTemplate(test.script,
[]pkformat{test.format})
if err != nil {
if err != test.err {