Replace ScriptToAddress with ScriptToAddrHash to return an address hash.
This commit is contained in:
parent
52a1488eaf
commit
83a19b239d
3 changed files with 60 additions and 68 deletions
59
address.go
59
address.go
|
@ -4,11 +4,6 @@
|
||||||
|
|
||||||
package btcscript
|
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
|
// 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.
|
// returned from ScriptToAddress as part of the metadata about the script.
|
||||||
// It implements the Stringer interface for nice printing.
|
// It implements the Stringer interface for nice printing.
|
||||||
|
@ -62,8 +57,8 @@ const (
|
||||||
scrNoAddr
|
scrNoAddr
|
||||||
)
|
)
|
||||||
|
|
||||||
// ScriptToAddress extracts a payment address and the type out of a PkScript
|
// ScriptToAddrHash extracts a 20-byte public key hash and the type out of a PkScript
|
||||||
func ScriptToAddress(script []byte) (ScriptType, string, error) {
|
func ScriptToAddrHash(script []byte) (ScriptType, []byte, error) {
|
||||||
// Currently this only understands one form of PkScript
|
// Currently this only understands one form of PkScript
|
||||||
validformats := []pkformat{
|
validformats := []pkformat{
|
||||||
{ScriptAddr, scrPayAddr, 25, []pkbytes{{0, OP_DUP}, {1, OP_HASH160}, {2, OP_DATA_20}, {23, OP_EQUALVERIFY}, {24, OP_CHECKSIG}}, true},
|
{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_DATA_32}}, false},
|
||||||
{ScriptStrange, scrNoAddr, 33, []pkbytes{{0, OP_HASH160}, {1, OP_DATA_20}, {22, OP_EQUAL}}, 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 format pkformat
|
||||||
var success bool
|
var success bool
|
||||||
for _, format = range validformats {
|
for _, format = range validformats {
|
||||||
|
@ -109,7 +104,7 @@ func scriptToAddressTemplate(script []byte, validformats []pkformat) (ScriptType
|
||||||
success = true
|
success = true
|
||||||
for _, pkbyte := range format.databytes {
|
for _, pkbyte := range format.databytes {
|
||||||
if pkbyte.off >= len(script) {
|
if pkbyte.off >= len(script) {
|
||||||
return ScriptUnknown, "Unknown",
|
return ScriptUnknown, nil,
|
||||||
StackErrInvalidAddrOffset
|
StackErrInvalidAddrOffset
|
||||||
}
|
}
|
||||||
if script[pkbyte.off] != pkbyte.val {
|
if script[pkbyte.off] != pkbyte.val {
|
||||||
|
@ -129,64 +124,50 @@ func scriptToAddressTemplate(script []byte, validformats []pkformat) (ScriptType
|
||||||
if len(script) > 1 {
|
if len(script) > 1 {
|
||||||
// check for a few special case
|
// check for a few special case
|
||||||
if script[len(script)-1] == OP_CHECK_MULTISIG {
|
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) {
|
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 {
|
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 {
|
if script[0] == OP_DATA_36 && len(script) == 37 {
|
||||||
// Multisig ScriptSig
|
// Multisig ScriptSig
|
||||||
return ScriptStrange, "Unknown", nil
|
return ScriptStrange, nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ScriptUnknown, "Unknown", StackErrUnknownAddress
|
return ScriptUnknown, nil, StackErrUnknownAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
var atype byte
|
var addrhash []byte
|
||||||
var abuf []byte
|
|
||||||
var addr string
|
|
||||||
switch format.parsetype {
|
switch format.parsetype {
|
||||||
case scrPayAddr:
|
case scrPayAddr:
|
||||||
atype = 0x00
|
addrhash = script[3:23]
|
||||||
abuf = script[3:23]
|
|
||||||
case scrCollectAddr:
|
case scrCollectAddr:
|
||||||
// script is replaced with the md160 of the pubkey
|
// script is replaced with the md160 of the pubkey
|
||||||
slen := len(script)
|
slen := len(script)
|
||||||
pubkey := script[slen-65:]
|
pubkey := script[slen-65:]
|
||||||
abuf = calcHash160(pubkey)
|
addrhash = calcHash160(pubkey)
|
||||||
case scrCollectAddrComp:
|
case scrCollectAddrComp:
|
||||||
// script is replaced with the md160 of the pubkey
|
// script is replaced with the md160 of the pubkey
|
||||||
slen := len(script)
|
slen := len(script)
|
||||||
pubkey := script[slen-33:]
|
pubkey := script[slen-33:]
|
||||||
abuf = calcHash160(pubkey)
|
addrhash = calcHash160(pubkey)
|
||||||
case scrGeneratePubkeyAddr:
|
case scrGeneratePubkeyAddr:
|
||||||
atype = 0x00
|
// unable to determine address hash from script
|
||||||
addr = "Unknown"
|
|
||||||
case scrNoAddr:
|
case scrNoAddr:
|
||||||
addr = "Unknown"
|
// unable to determine address hash from script
|
||||||
case scrPubkeyAddr:
|
case scrPubkeyAddr:
|
||||||
atype = 0x00
|
|
||||||
pubkey := script[1:66]
|
pubkey := script[1:66]
|
||||||
abuf = calcHash160(pubkey)
|
addrhash = calcHash160(pubkey)
|
||||||
case scrPubkeyAddrComp:
|
case scrPubkeyAddrComp:
|
||||||
atype = 0x00
|
|
||||||
pubkey := script[1:34]
|
pubkey := script[1:34]
|
||||||
abuf = calcHash160(pubkey)
|
addrhash = calcHash160(pubkey)
|
||||||
default:
|
default:
|
||||||
return ScriptUnknown, "Unknown", StackErrInvalidParseType
|
return ScriptUnknown, nil, StackErrInvalidParseType
|
||||||
}
|
}
|
||||||
|
|
||||||
if abuf != nil {
|
return format.addrtype, addrhash, nil
|
||||||
addrbytes := append([]byte{atype}, abuf[:]...)
|
|
||||||
|
|
||||||
cksum := btcwire.DoubleSha256(addrbytes)
|
|
||||||
addrbytes = append(addrbytes, cksum[:4]...)
|
|
||||||
addr = btcutil.Base58Encode(addrbytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
return format.addrtype, addr, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
package btcscript_test
|
package btcscript_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"github.com/conformal/btcscript"
|
"github.com/conformal/btcscript"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type addressTest struct {
|
type addressTest struct {
|
||||||
script []byte
|
script []byte
|
||||||
address string
|
addrhash []byte
|
||||||
shouldFail error
|
shouldFail error
|
||||||
class btcscript.ScriptType
|
class btcscript.ScriptType
|
||||||
}
|
}
|
||||||
|
@ -26,7 +27,9 @@ var addressTests = []addressTest{
|
||||||
0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f,
|
0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f,
|
||||||
0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12,
|
0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12,
|
||||||
0xa3, btcscript.OP_CHECKSIG},
|
0xa3, btcscript.OP_CHECKSIG},
|
||||||
address: "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S",
|
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,
|
class: btcscript.ScriptPubKey,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_DATA_65,
|
{script: []byte{btcscript.OP_DATA_65,
|
||||||
|
@ -51,7 +54,7 @@ var addressTests = []addressTest{
|
||||||
0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c,
|
0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c,
|
||||||
0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22,
|
0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22,
|
||||||
0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01},
|
0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01},
|
||||||
address: "Unknown",
|
addrhash: nil,
|
||||||
class: btcscript.ScriptPubKey,
|
class: btcscript.ScriptPubKey,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_DUP, btcscript.OP_HASH160,
|
{script: []byte{btcscript.OP_DUP, btcscript.OP_HASH160,
|
||||||
|
@ -61,7 +64,9 @@ var addressTests = []addressTest{
|
||||||
0x09, 0xa3, 0x05, 0x64,
|
0x09, 0xa3, 0x05, 0x64,
|
||||||
btcscript.OP_EQUALVERIFY, btcscript.OP_CHECKSIG,
|
btcscript.OP_EQUALVERIFY, btcscript.OP_CHECKSIG,
|
||||||
},
|
},
|
||||||
address: "1Gmt8AzabtngttF3PcZzLR1p7uCMaHNuGY",
|
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,
|
class: btcscript.ScriptAddr,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_DATA_73,
|
{script: []byte{btcscript.OP_DATA_73,
|
||||||
|
@ -85,7 +90,9 @@ var addressTests = []addressTest{
|
||||||
0x93, 0x7d, 0x58, 0xe5, 0xa7, 0x5a, 0x71, 0x04,
|
0x93, 0x7d, 0x58, 0xe5, 0xa7, 0x5a, 0x71, 0x04,
|
||||||
0x2d, 0x40, 0x38, 0x8a, 0x4d, 0x30, 0x7f, 0x88,
|
0x2d, 0x40, 0x38, 0x8a, 0x4d, 0x30, 0x7f, 0x88,
|
||||||
0x7d},
|
0x7d},
|
||||||
address: "16tRBxwU7t5hEHaPLqiE35gS3jaGBppraH",
|
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,
|
class: btcscript.ScriptAddr,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_DATA_73,
|
{script: []byte{btcscript.OP_DATA_73,
|
||||||
|
@ -106,7 +113,9 @@ var addressTests = []addressTest{
|
||||||
0x72, 0x3d, 0x5a, 0xd4, 0x06, 0x8d, 0xdd, 0x30,
|
0x72, 0x3d, 0x5a, 0xd4, 0x06, 0x8d, 0xdd, 0x30,
|
||||||
0x36,
|
0x36,
|
||||||
},
|
},
|
||||||
address: "1272555ceTPn2WepjzVgFESWdfNQjqdjgp",
|
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,
|
class: btcscript.ScriptAddr,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_DATA_32,
|
{script: []byte{btcscript.OP_DATA_32,
|
||||||
|
@ -115,7 +124,7 @@ var addressTests = []addressTest{
|
||||||
0x87, 0x2a, 0xb9, 0xd3, 0x2c, 0xdc, 0x08, 0x33,
|
0x87, 0x2a, 0xb9, 0xd3, 0x2c, 0xdc, 0x08, 0x33,
|
||||||
0x80, 0x73, 0x3e, 0x3e, 0x98, 0x47, 0xff, 0x77,
|
0x80, 0x73, 0x3e, 0x3e, 0x98, 0x47, 0xff, 0x77,
|
||||||
},
|
},
|
||||||
address: "Unknown",
|
addrhash: nil,
|
||||||
class: btcscript.ScriptStrange,
|
class: btcscript.ScriptStrange,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_DATA_33,
|
{script: []byte{btcscript.OP_DATA_33,
|
||||||
|
@ -126,7 +135,9 @@ var addressTests = []addressTest{
|
||||||
0x36,
|
0x36,
|
||||||
btcscript.OP_CHECKSIG,
|
btcscript.OP_CHECKSIG,
|
||||||
},
|
},
|
||||||
address: "1272555ceTPn2WepjzVgFESWdfNQjqdjgp",
|
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,
|
class: btcscript.ScriptPubKey,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_DATA_33,
|
{script: []byte{btcscript.OP_DATA_33,
|
||||||
|
@ -137,7 +148,7 @@ var addressTests = []addressTest{
|
||||||
0x36,
|
0x36,
|
||||||
btcscript.OP_CHECK_MULTISIG, // note this isn't a real tx
|
btcscript.OP_CHECK_MULTISIG, // note this isn't a real tx
|
||||||
},
|
},
|
||||||
address: "Unknown",
|
addrhash: nil,
|
||||||
class: btcscript.ScriptStrange,
|
class: btcscript.ScriptStrange,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_0, btcscript.OP_DATA_33,
|
{script: []byte{btcscript.OP_0, btcscript.OP_DATA_33,
|
||||||
|
@ -147,7 +158,7 @@ var addressTests = []addressTest{
|
||||||
0x72, 0x3d, 0x5a, 0xd4, 0x06, 0x8d, 0xdd, 0x30,
|
0x72, 0x3d, 0x5a, 0xd4, 0x06, 0x8d, 0xdd, 0x30,
|
||||||
0x36, // note this isn't a real tx
|
0x36, // note this isn't a real tx
|
||||||
},
|
},
|
||||||
address: "Unknown",
|
addrhash: nil,
|
||||||
class: btcscript.ScriptStrange,
|
class: btcscript.ScriptStrange,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_HASH160, btcscript.OP_DATA_20,
|
{script: []byte{btcscript.OP_HASH160, btcscript.OP_DATA_20,
|
||||||
|
@ -156,7 +167,7 @@ var addressTests = []addressTest{
|
||||||
0xa7, 0xa8, 0x45, 0xbd,
|
0xa7, 0xa8, 0x45, 0xbd,
|
||||||
btcscript.OP_EQUAL, // note this isn't a real tx
|
btcscript.OP_EQUAL, // note this isn't a real tx
|
||||||
},
|
},
|
||||||
address: "Unknown",
|
addrhash: nil,
|
||||||
class: btcscript.ScriptStrange,
|
class: btcscript.ScriptStrange,
|
||||||
},
|
},
|
||||||
{script: []byte{btcscript.OP_DATA_36,
|
{script: []byte{btcscript.OP_DATA_36,
|
||||||
|
@ -167,7 +178,7 @@ var addressTests = []addressTest{
|
||||||
0xa7, 0xa8, 0x45, 0xbd,
|
0xa7, 0xa8, 0x45, 0xbd,
|
||||||
// note this isn't a real tx
|
// note this isn't a real tx
|
||||||
},
|
},
|
||||||
address: "Unknown",
|
addrhash: nil,
|
||||||
class: btcscript.ScriptStrange,
|
class: btcscript.ScriptStrange,
|
||||||
},
|
},
|
||||||
{script: []byte{},
|
{script: []byte{},
|
||||||
|
@ -177,7 +188,7 @@ var addressTests = []addressTest{
|
||||||
|
|
||||||
func TestAddresses(t *testing.T) {
|
func TestAddresses(t *testing.T) {
|
||||||
for i, s := range addressTests {
|
for i, s := range addressTests {
|
||||||
class, address, err := btcscript.ScriptToAddress(s.script)
|
class, addrhash, err := btcscript.ScriptToAddrHash(s.script)
|
||||||
if s.shouldFail != nil {
|
if s.shouldFail != nil {
|
||||||
if err != s.shouldFail {
|
if err != s.shouldFail {
|
||||||
t.Errorf("Address test %v failed is err [%v] should be [%v]", i, 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 {
|
if err != nil {
|
||||||
t.Errorf("Address test %v failed err %v", i, err)
|
t.Errorf("Address test %v failed err %v", i, err)
|
||||||
} else {
|
} else {
|
||||||
if s.address != address {
|
if !bytes.Equal(s.addrhash, addrhash) {
|
||||||
t.Errorf("Address test %v mismatch is [%v] want [%v]", i, address, s.address)
|
t.Errorf("Address test %v mismatch is [%v] want [%v]", i, addrhash, s.addrhash)
|
||||||
}
|
}
|
||||||
if s.class != class {
|
if s.class != class {
|
||||||
t.Errorf("Address test %v class mismatch is [%v] want [%v]", i, class, s.class)
|
t.Errorf("Address test %v class mismatch is [%v] want [%v]", i, class, s.class)
|
||||||
|
|
|
@ -49,8 +49,8 @@ func TstSignatureScriptCustomReader(reader io.Reader, tx *btcwire.MsgTx, idx int
|
||||||
hashType, privkey, compress)
|
hashType, privkey, compress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests for internal error cases in ScriptToAddress.
|
// Tests for internal error cases in ScriptToAddrHash.
|
||||||
// We pass bad format definitions to ScriptToAddrss to make sure the internal
|
// 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
|
// 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
|
// because of the ridiculous amount of internal types/constants that would
|
||||||
// otherwise need to be exported here.
|
// otherwise need to be exported here.
|
||||||
|
@ -94,7 +94,7 @@ var TstPkFormats = []pkformatTest{
|
||||||
|
|
||||||
func TestBadPkFormat(t *testing.T) {
|
func TestBadPkFormat(t *testing.T) {
|
||||||
for _, test := range TstPkFormats {
|
for _, test := range TstPkFormats {
|
||||||
ty, addr, err := scriptToAddressTemplate(test.script,
|
ty, addr, err := scriptToAddrHashTemplate(test.script,
|
||||||
[]pkformat{test.format})
|
[]pkformat{test.format})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != test.err {
|
if err != test.err {
|
||||||
|
|
Loading…
Reference in a new issue