From 092aeef2ed7093fc560511765dd7ce5ffdf33c6e Mon Sep 17 00:00:00 2001 From: Jakub Matys Date: Tue, 29 May 2018 19:08:17 +0200 Subject: [PATCH] CashAddr decoding optimization - doesn't support multisig --- bchain/baseparser.go | 5 --- bchain/coins/bch/bcashparser.go | 55 +++++++++++++------------- bchain/coins/bch/bcashparser_test.go | 24 +++++------ bchain/coins/btc/bitcoinparser.go | 15 ++++--- bchain/coins/btc/bitcoinparser_test.go | 7 ++-- bchain/types.go | 1 - 6 files changed, 52 insertions(+), 55 deletions(-) diff --git a/bchain/baseparser.go b/bchain/baseparser.go index 896de7e5..dfba4ea9 100644 --- a/bchain/baseparser.go +++ b/bchain/baseparser.go @@ -19,11 +19,6 @@ func (p *BaseParser) AddressToOutputScript(address string) ([]byte, error) { return nil, errors.New("AddressToOutputScript: not implemented") } -// OutputScriptToAddresses converts ScriptPubKey to addresses - currently not implemented -func (p *BaseParser) OutputScriptToAddresses(script []byte) ([]string, error) { - return nil, errors.New("OutputScriptToAddresses: not implemented") -} - // ParseBlock parses raw block to our Block struct - currently not implemented func (p *BaseParser) ParseBlock(b []byte) (*Block, error) { return nil, errors.New("ParseBlock: not implemented") diff --git a/bchain/coins/bch/bcashparser.go b/bchain/coins/bch/bcashparser.go index 5fbdffb1..2be69fa4 100644 --- a/bchain/coins/bch/bcashparser.go +++ b/bchain/coins/bch/bcashparser.go @@ -4,7 +4,6 @@ import ( "blockbook/bchain" "blockbook/bchain/coins/btc" "fmt" - "strings" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" @@ -20,7 +19,11 @@ const ( CashAddr ) -var prefixes = []string{"bitcoincash", "bchtest", "bchreg"} +const ( + MainNetPrefix = "bitcoincash:" + TestNetPrefix = "bchtest:" + RegTestPrefix = "bchreg:" +) // BCashParser handle type BCashParser struct { @@ -44,10 +47,11 @@ func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) (*BCashParser p := &BCashParser{ BitcoinParser: &btc.BitcoinParser{ BaseParser: &bchain.BaseParser{ - AddressFactory: func(addr string) (bchain.Address, error) { return newBCashAddress(addr, params, format) }, + AddressFactory: func(addr string) (bchain.Address, error) { return newBCashAddress(addr, format) }, BlockAddressesToKeep: c.BlockAddressesToKeep, }, - Params: params, + Params: params, + OutputScriptToAddresses: outputScriptToAddresses, }, AddressFormat: format, } @@ -105,42 +109,37 @@ func (p *BCashParser) AddressToOutputScript(address string) ([]byte, error) { } func isCashAddr(addr string) bool { - slice := strings.Split(addr, ":") - if len(slice) != 2 { - return false - } - for _, prefix := range prefixes { - if slice[0] == prefix { - return true - } + n := len(addr) + switch { + case n > len(MainNetPrefix) && addr[0:len(MainNetPrefix)] == MainNetPrefix: + return true + case n > len(TestNetPrefix) && addr[0:len(TestNetPrefix)] == TestNetPrefix: + return true + case n > len(RegTestPrefix) && addr[0:len(RegTestPrefix)] == RegTestPrefix: + return true } + return false } -func (p *BCashParser) UnpackTx(buf []byte) (tx *bchain.Tx, height uint32, err error) { - tx, height, err = p.BitcoinParser.UnpackTx(buf) +// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses +func outputScriptToAddresses(script []byte, params *chaincfg.Params) ([]string, error) { + a, err := bchutil.ExtractPkScriptAddrs(script, params) if err != nil { - return + return nil, err } - - for i, vout := range tx.Vout { - if len(vout.ScriptPubKey.Addresses) == 1 { - a, err := newBCashAddress(vout.ScriptPubKey.Addresses[0], p.Params, p.AddressFormat) - if err != nil { - return nil, 0, err - } - tx.Vout[i].Address = a - } - } - - return + return []string{a.EncodeAddress()}, nil } type bcashAddress struct { addr string } -func newBCashAddress(addr string, net *chaincfg.Params, format AddressFormat) (*bcashAddress, error) { +func newBCashAddress(addr string, format AddressFormat) (*bcashAddress, error) { + if isCashAddr(addr) && format == CashAddr { + return &bcashAddress{addr: addr}, nil + } + da, err := address.NewFromString(addr) if err != nil { return nil, err diff --git a/bchain/coins/bch/bcashparser_test.go b/bchain/coins/bch/bcashparser_test.go index aa9c1186..5ef506f7 100644 --- a/bchain/coins/bch/bcashparser_test.go +++ b/bchain/coins/bch/bcashparser_test.go @@ -10,7 +10,7 @@ import ( ) func TestBcashAddressEncodeAddress(t *testing.T) { - addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy) + addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", Legacy) if err != nil { t.Errorf("newBCashAddress() error = %v", err) return @@ -19,7 +19,7 @@ func TestBcashAddressEncodeAddress(t *testing.T) { if got1 != "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji" { t.Errorf("String() got1 = %v, want %v", got1, "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji") } - addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr) + addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", CashAddr) if err != nil { t.Errorf("newBCashAddress() error = %v", err) return @@ -31,12 +31,12 @@ func TestBcashAddressEncodeAddress(t *testing.T) { } func TestBcashAddressAreEqual(t *testing.T) { - addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy) + addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", Legacy) if err != nil { t.Errorf("newBCashAddress() error = %v", err) return } - addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr) + addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", CashAddr) if err != nil { t.Errorf("newBCashAddress() error = %v", err) return @@ -60,12 +60,12 @@ func TestBcashAddressAreEqual(t *testing.T) { } func TestBcashAddressInSlice(t *testing.T) { - addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy) + addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", Legacy) if err != nil { t.Errorf("newBCashAddress() error = %v", err) return } - addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr) + addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", CashAddr) if err != nil { t.Errorf("newBCashAddress() error = %v", err) return @@ -128,12 +128,12 @@ func init() { addr1, addr2, addr3 bchain.Address err error ) - addr1, err = newBCashAddress("3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", GetChainParams("main"), Legacy) + addr1, err = newBCashAddress("3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", Legacy) if err == nil { - addr2, err = newBCashAddress("2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", GetChainParams("test"), Legacy) + addr2, err = newBCashAddress("2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", Legacy) } if err == nil { - addr3, err = newBCashAddress("2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", GetChainParams("test"), Legacy) + addr3, err = newBCashAddress("2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", Legacy) } if err != nil { panic(err) @@ -161,7 +161,7 @@ func init() { ScriptPubKey: bchain.ScriptPubKey{ Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87", Addresses: []string{ - "3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", + "bitcoincash:pps5f4tu3tl5sjfvnhaeznsjpvst44eddugfcnqpy9", }, }, Address: addr1, @@ -191,7 +191,7 @@ func init() { ScriptPubKey: bchain.ScriptPubKey{ Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887", Addresses: []string{ - "2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", + "bchtest:prxkdrtcrm8xqrh6fvjqfhy3l5nt3w9wmq9fmsvkmz", }, }, Address: addr2, @@ -202,7 +202,7 @@ func init() { ScriptPubKey: bchain.ScriptPubKey{ Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87", Addresses: []string{ - "2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", + "bchtest:pqjxv4dah42v0erh6r4zxa0gdcxm9w8cpg0qw8tqf6", }, }, Address: addr3, diff --git a/bchain/coins/btc/bitcoinparser.go b/bchain/coins/btc/bitcoinparser.go index 442bcfa5..aa8ceffe 100644 --- a/bchain/coins/btc/bitcoinparser.go +++ b/bchain/coins/btc/bitcoinparser.go @@ -14,10 +14,14 @@ import ( "github.com/btcsuite/btcutil" ) +// OutputScriptToAddressesFunc converts ScriptPubKey to bitcoin addresses +type OutputScriptToAddressesFunc func(script []byte, params *chaincfg.Params) ([]string, error) + // BitcoinParser handle type BitcoinParser struct { *bchain.BaseParser - Params *chaincfg.Params + Params *chaincfg.Params + OutputScriptToAddresses OutputScriptToAddressesFunc } // NewBitcoinParser returns new BitcoinParser instance @@ -28,6 +32,7 @@ func NewBitcoinParser(params *chaincfg.Params, c *Configuration) *BitcoinParser BlockAddressesToKeep: c.BlockAddressesToKeep, }, params, + outputScriptToAddresses, } } @@ -67,9 +72,9 @@ func (p *BitcoinParser) AddressToOutputScript(address string) ([]byte, error) { return script, nil } -// OutputScriptToAddresses converts ScriptPubKey to bitcoin addresses -func (p *BitcoinParser) OutputScriptToAddresses(script []byte) ([]string, error) { - _, addresses, _, err := txscript.ExtractPkScriptAddrs(script, p.Params) +// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses +func outputScriptToAddresses(script []byte, params *chaincfg.Params) ([]string, error) { + _, addresses, _, err := txscript.ExtractPkScriptAddrs(script, params) if err != nil { return nil, err } @@ -105,7 +110,7 @@ func (p *BitcoinParser) txFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.T for i, out := range t.TxOut { addrs := []string{} if parseAddresses { - addrs, _ = p.OutputScriptToAddresses(out.PkScript) + addrs, _ = p.OutputScriptToAddresses(out.PkScript, p.Params) } s := bchain.ScriptPubKey{ Hex: hex.EncodeToString(out.PkScript), diff --git a/bchain/coins/btc/bitcoinparser_test.go b/bchain/coins/btc/bitcoinparser_test.go index 6c3606d4..669a4927 100644 --- a/bchain/coins/btc/bitcoinparser_test.go +++ b/bchain/coins/btc/bitcoinparser_test.go @@ -94,17 +94,16 @@ func TestOutputScriptToAddresses(t *testing.T) { wantErr: false, }, } - parser := NewBitcoinParser(GetChainParams("main"), &Configuration{}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { b, _ := hex.DecodeString(tt.args.script) - got, err := parser.OutputScriptToAddresses(b) + got, err := outputScriptToAddresses(b, GetChainParams("main")) if (err != nil) != tt.wantErr { - t.Errorf("OutputScriptToAddresses() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("outputScriptToAddresses() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("OutputScriptToAddresses() = %v, want %v", got, tt.want) + t.Errorf("outputScriptToAddresses() = %v, want %v", got, tt.want) } }) } diff --git a/bchain/types.go b/bchain/types.go index 7f9ba636..0edd8ef7 100644 --- a/bchain/types.go +++ b/bchain/types.go @@ -156,7 +156,6 @@ type BlockChainParser interface { GetAddrIDFromAddress(address string) ([]byte, error) // address to output script conversions AddressToOutputScript(address string) ([]byte, error) - OutputScriptToAddresses(script []byte) ([]string, error) // transactions PackedTxidLen() int PackTxid(txid string) ([]byte, error)