From d371675a90ce9c1cd4660ff5533897b2a6a5ed98 Mon Sep 17 00:00:00 2001 From: OPReturnCode Date: Tue, 13 May 2025 21:13:48 +0100 Subject: [PATCH 1/6] Fix bug in the flow of handling addresses containing a 32-byte hash --- address.go | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/address.go b/address.go index 1942c2d..4d5c827 100644 --- a/address.go +++ b/address.go @@ -100,16 +100,16 @@ func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) { switch len(decoded) { case ripemd160.Size: // P2PKH or P2SH switch typ { - case AddrTypePayToPubKeyHash: + case AddrTypePayToPubKeyHash, AddrTypeTokenPayToPubKeyHash: return newAddressPubKeyHash(decoded, defaultNet) - case AddrTypePayToScriptHash: + case AddrTypePayToScriptHash, AddrTypeTokenPayToScriptHash: return newAddressScriptHashFromHash(decoded, defaultNet) default: return nil, ErrUnknownAddressType } case sha256.Size: // P2SH32 switch typ { - case AddrTypePayToScriptHash32: + case AddrTypePayToScriptHash, AddrTypeTokenPayToScriptHash: return newAddressScriptHash32FromHash(decoded, defaultNet) default: return nil, ErrUnknownAddressType @@ -139,7 +139,7 @@ func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) { } case sha256.Size: // P2SH32 switch typ { - case AddrTypePayToScriptHash32: + case AddrTypeTokenPayToScriptHash: return NewSlpAddressScriptHash32FromHash(decoded, defaultNet) default: return nil, ErrUnknownAddressType @@ -759,16 +759,21 @@ func checkDecodeCashAddress(input string) (result []byte, prefix string, t Addre if err != nil { return data, prefix, AddrTypePayToPubKeyHash, err } - if len(data) != 21 { + if len(data) != 21 && len(data) != 33 { // version byte + ripemd160.Size or sha256.Size return data, prefix, AddrTypePayToPubKeyHash, errors.New("incorrect data length") } - switch data[0] { - case 0x00: + + switch data[0] >> 3 { // bits 1 to 4 are the address type. + case 0: t = AddrTypePayToPubKeyHash - case 0x08: + case 1: t = AddrTypePayToScriptHash + case 2: + t = AddrTypeTokenPayToPubKeyHash + case 3: + t = AddrTypeTokenPayToScriptHash } - return data[1:21], prefix, t, nil + return data[1:], prefix, t, nil } // AddressType represents the type of address and is used @@ -784,9 +789,13 @@ const ( // a cashaddr PayToPubkeyHash address AddrTypePayToScriptHash AddressType = 1 - // AddrTypePayToScriptHash32 is the numeric identifier for - // a cashaddr PayToPubkeyHash address - AddrTypePayToScriptHash32 AddressType = 2 + // AddrTypePayToScriptHash is the numeric identifier for + // a token aware cashaddr PayToPubkeyHash address + AddrTypeTokenPayToPubKeyHash AddressType = 2 + + // AddrTypeTokenPayToScriptHash is the numeric identifier for + // a token aware cashaddr PayToPubkeyHash address + AddrTypeTokenPayToScriptHash AddressType = 3 ) // Charset is the base32 character set for the cashaddr. From 5781ffc2f1eda7a55288a78a294ab40c29f5025b Mon Sep 17 00:00:00 2001 From: OPReturnCode Date: Tue, 13 May 2025 22:32:55 +0100 Subject: [PATCH 2/6] Add test vectors for the modified address types --- address_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/address_test.go b/address_test.go index d96daff..8025047 100644 --- a/address_test.go +++ b/address_test.go @@ -1017,3 +1017,57 @@ func TestConvertSlpToCashAddressP2sh(t *testing.T) { t.Fatal("incorrect conversion") } } + +// Source: https://github.com/cashtokens/cashtokens/blob/master/test-vectors/cashaddr.json +var p2SH32CashAddreTestVectors = []string{ + "bitcoincash:qr6m7j9njldwwzlg9v7v53unlr4jkmx6eylep8ekg2", + "bitcoincash:zr6m7j9njldwwzlg9v7v53unlr4jkmx6eycnjehshe", + "bchtest:pr6m7j9njldwwzlg9v7v53unlr4jkmx6eyvwc0uz5t", + "pref:pr6m7j9njldwwzlg9v7v53unlr4jkmx6ey65nvtks5", + "bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl", + "bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v", + "bchtest:qr7fzmep8g7h7ymfxy74lgc0v950j3r295pdnvy3hr", + "bchtest:zr7fzmep8g7h7ymfxy74lgc0v950j3r295x8qj2hgs", + "bchreg:qr7fzmep8g7h7ymfxy74lgc0v950j3r295m39d8z59", + "bchreg:zr7fzmep8g7h7ymfxy74lgc0v950j3r295umknfytk", + "prefix:qr7fzmep8g7h7ymfxy74lgc0v950j3r295fu6e430r", + "prefix:zr7fzmep8g7h7ymfxy74lgc0v950j3r295wkf8mhss", + "bitcoincash:qpagr634w55t4wp56ftxx53xukhqgl24yse53qxdge", + "bitcoincash:zpagr634w55t4wp56ftxx53xukhqgl24ys77z7gth2", + "bitcoincash:qq9l9e2dgkx0hp43qm3c3h252e9euugrfc6vlt3r9e", + "bitcoincash:zq9l9e2dgkx0hp43qm3c3h252e9euugrfcaxv4l962", + "bitcoincash:qre24q38ghy6k3pegpyvtxahu8q8hqmxmqqn28z85p", + "bitcoincash:zre24q38ghy6k3pegpyvtxahu8q8hqmxmq8eeevptj", + "bitcoincash:qz7xc0vl85nck65ffrsx5wvewjznp9lflgktxc5878", + "bitcoincash:zz7xc0vl85nck65ffrsx5wvewjznp9lflg3p4x6pp5", + "bitcoincash:ppawqn2h74a4t50phuza84kdp3794pq3ccvm92p8sh", + "bitcoincash:rpawqn2h74a4t50phuza84kdp3794pq3cct3k50p0y", + "bitcoincash:pqv53dwyatxse2xh7nnlqhyr6ryjgfdtagkd4vc388", + "bitcoincash:rqv53dwyatxse2xh7nnlqhyr6ryjgfdtag38xjkhc5", + "bitcoincash:prseh0a4aejjcewhc665wjqhppgwrz2lw5txgn666a", + "bitcoincash:rrseh0a4aejjcewhc665wjqhppgwrz2lw5vvmd5u9w", + "bitcoincash:pzltaslh7xnrsxeqm7qtvh0v53n3gfk0v5wwf6d7j4", + "bitcoincash:rzltaslh7xnrsxeqm7qtvh0v53n3gfk0v5fy6yrcdx", + "bitcoincash:pvqqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqpkp7fqn0", + "bitcoincash:rvqqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqn9alsp2y", + "bitcoincash:pdzyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3jh2p5nn", + "bitcoincash:rdzyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygrpttc42c", + "bitcoincash:pwyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsh3sujgcr", + "bitcoincash:rwyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9zvatfpg", + "bitcoincash:p0xvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvcm6gz4t77", + "bitcoincash:r0xvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvcff5rv284", + "bitcoincash:p0llllllllllllllllllllllllllllllllllllllllllllllllll7x3vthu35", + "bitcoincash:r0llllllllllllllllllllllllllllllllllllllllllllllllll75zs2wagl", + "bitcoincash:qvch8mmxy0rtfrlarg7ucrxxfzds5pamg73h7370aa87d80gyhqxq5nlegake", + "bchtest:pvch8mmxy0rtfrlarg7ucrxxfzds5pamg73h7370aa87d80gyhqxq7fqng6m6", + "pref:pvch8mmxy0rtfrlarg7ucrxxfzds5pamg73h7370aa87d80gyhqxq4k9m7qf9", +} + +func TestP2SH32CashAddreTestVectors(t *testing.T) { + for _, s := range p2SH32CashAddreTestVectors { + _, _, err := bchutil.DecodeCashAddress(s) + if err != nil { + t.Error(err) + } + } +} From bc663d2df04c5c7f2a9beb42a8a6054a96de2ac1 Mon Sep 17 00:00:00 2001 From: OPReturnCode Date: Tue, 13 May 2025 23:30:22 +0100 Subject: [PATCH 3/6] Update TestP2SH32CashAddreTestVectors to perform a broader check --- address_test.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/address_test.go b/address_test.go index 8025047..64f43ba 100644 --- a/address_test.go +++ b/address_test.go @@ -1058,16 +1058,26 @@ var p2SH32CashAddreTestVectors = []string{ "bitcoincash:r0xvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvcff5rv284", "bitcoincash:p0llllllllllllllllllllllllllllllllllllllllllllllllll7x3vthu35", "bitcoincash:r0llllllllllllllllllllllllllllllllllllllllllllllllll75zs2wagl", - "bitcoincash:qvch8mmxy0rtfrlarg7ucrxxfzds5pamg73h7370aa87d80gyhqxq5nlegake", "bchtest:pvch8mmxy0rtfrlarg7ucrxxfzds5pamg73h7370aa87d80gyhqxq7fqng6m6", "pref:pvch8mmxy0rtfrlarg7ucrxxfzds5pamg73h7370aa87d80gyhqxq4k9m7qf9", } func TestP2SH32CashAddreTestVectors(t *testing.T) { for _, s := range p2SH32CashAddreTestVectors { - _, _, err := bchutil.DecodeCashAddress(s) + result := strings.Split(s, ":") + params := &chaincfg.MainNetParams + switch result[0] { + case "bchtest": + params = &chaincfg.TestNet4Params + case "bchreg": + params = &chaincfg.RegressionNetParams + case "prefix", "pref": + continue + + } + _, err := bchutil.DecodeAddress(s, params) if err != nil { t.Error(err) } } -} +} \ No newline at end of file From 0300b85ae31787bbb3a204c925502ebab043c764 Mon Sep 17 00:00:00 2001 From: OPReturnCode Date: Tue, 13 May 2025 23:33:10 +0100 Subject: [PATCH 4/6] Format file --- address_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/address_test.go b/address_test.go index 64f43ba..11deca7 100644 --- a/address_test.go +++ b/address_test.go @@ -1080,4 +1080,4 @@ func TestP2SH32CashAddreTestVectors(t *testing.T) { t.Error(err) } } -} \ No newline at end of file +} From a73ef6afaf8b9672477d59088f82b30ca04fdc96 Mon Sep 17 00:00:00 2001 From: OPReturnCode Date: Tue, 13 May 2025 23:49:21 +0100 Subject: [PATCH 5/6] Add invalid test vectors --- address_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/address_test.go b/address_test.go index 11deca7..304a3fc 100644 --- a/address_test.go +++ b/address_test.go @@ -1081,3 +1081,21 @@ func TestP2SH32CashAddreTestVectors(t *testing.T) { } } } + +var invalidAddreTestVectors = []string{ + "bitcoincash:prseh0a4aejjcewhc665wjqhppgwrz2lw5txgn676a", + "bitcoincash:rrseh0a4aejjcewhc665wjqhppgwrz2lw5vVmd5u9w", + "bitcoincash:izltaslh7xnrsxeqm7qtvh0v53n3gfk0v5wwf6d7j4", + "bitcoincash:pvqqqqqqqqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqpkp7fqn0", + "bitcoincash:rv0qqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqn9alsp2y", +} + +func TestInvalidCashAddressTestVectors(t *testing.T) { + for _, s := range invalidAddreTestVectors { + params := &chaincfg.MainNetParams + _, err := bchutil.DecodeAddress(s, params) + if err == nil { + t.Fatal("") + } + } +} From e891517447e36108a7f2e34251d94a3b32e7e084 Mon Sep 17 00:00:00 2001 From: OPReturnCode Date: Tue, 13 May 2025 23:53:44 +0100 Subject: [PATCH 6/6] Fix error message --- address_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/address_test.go b/address_test.go index 304a3fc..278873a 100644 --- a/address_test.go +++ b/address_test.go @@ -1095,7 +1095,7 @@ func TestInvalidCashAddressTestVectors(t *testing.T) { params := &chaincfg.MainNetParams _, err := bchutil.DecodeAddress(s, params) if err == nil { - t.Fatal("") + t.Fatalf("Failed to error on invalid address string: %s", s) } } }