CashAddr decoding optimization - doesn't support multisig

This commit is contained in:
Jakub Matys 2018-05-29 19:08:17 +02:00
parent 79ba6abadd
commit 092aeef2ed
6 changed files with 52 additions and 55 deletions

View File

@ -19,11 +19,6 @@ func (p *BaseParser) AddressToOutputScript(address string) ([]byte, error) {
return nil, errors.New("AddressToOutputScript: not implemented") 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 // ParseBlock parses raw block to our Block struct - currently not implemented
func (p *BaseParser) ParseBlock(b []byte) (*Block, error) { func (p *BaseParser) ParseBlock(b []byte) (*Block, error) {
return nil, errors.New("ParseBlock: not implemented") return nil, errors.New("ParseBlock: not implemented")

View File

@ -4,7 +4,6 @@ import (
"blockbook/bchain" "blockbook/bchain"
"blockbook/bchain/coins/btc" "blockbook/bchain/coins/btc"
"fmt" "fmt"
"strings"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
@ -20,7 +19,11 @@ const (
CashAddr CashAddr
) )
var prefixes = []string{"bitcoincash", "bchtest", "bchreg"} const (
MainNetPrefix = "bitcoincash:"
TestNetPrefix = "bchtest:"
RegTestPrefix = "bchreg:"
)
// BCashParser handle // BCashParser handle
type BCashParser struct { type BCashParser struct {
@ -44,10 +47,11 @@ func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) (*BCashParser
p := &BCashParser{ p := &BCashParser{
BitcoinParser: &btc.BitcoinParser{ BitcoinParser: &btc.BitcoinParser{
BaseParser: &bchain.BaseParser{ 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, BlockAddressesToKeep: c.BlockAddressesToKeep,
}, },
Params: params, Params: params,
OutputScriptToAddresses: outputScriptToAddresses,
}, },
AddressFormat: format, AddressFormat: format,
} }
@ -105,42 +109,37 @@ func (p *BCashParser) AddressToOutputScript(address string) ([]byte, error) {
} }
func isCashAddr(addr string) bool { func isCashAddr(addr string) bool {
slice := strings.Split(addr, ":") n := len(addr)
if len(slice) != 2 { switch {
return false case n > len(MainNetPrefix) && addr[0:len(MainNetPrefix)] == MainNetPrefix:
} return true
for _, prefix := range prefixes { case n > len(TestNetPrefix) && addr[0:len(TestNetPrefix)] == TestNetPrefix:
if slice[0] == prefix { return true
return true case n > len(RegTestPrefix) && addr[0:len(RegTestPrefix)] == RegTestPrefix:
} return true
} }
return false return false
} }
func (p *BCashParser) UnpackTx(buf []byte) (tx *bchain.Tx, height uint32, err error) { // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
tx, height, err = p.BitcoinParser.UnpackTx(buf) func outputScriptToAddresses(script []byte, params *chaincfg.Params) ([]string, error) {
a, err := bchutil.ExtractPkScriptAddrs(script, params)
if err != nil { if err != nil {
return return nil, err
} }
return []string{a.EncodeAddress()}, nil
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
} }
type bcashAddress struct { type bcashAddress struct {
addr string 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) da, err := address.NewFromString(addr)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -10,7 +10,7 @@ import (
) )
func TestBcashAddressEncodeAddress(t *testing.T) { func TestBcashAddressEncodeAddress(t *testing.T) {
addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy) addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", Legacy)
if err != nil { if err != nil {
t.Errorf("newBCashAddress() error = %v", err) t.Errorf("newBCashAddress() error = %v", err)
return return
@ -19,7 +19,7 @@ func TestBcashAddressEncodeAddress(t *testing.T) {
if got1 != "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji" { if got1 != "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji" {
t.Errorf("String() got1 = %v, want %v", 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 { if err != nil {
t.Errorf("newBCashAddress() error = %v", err) t.Errorf("newBCashAddress() error = %v", err)
return return
@ -31,12 +31,12 @@ func TestBcashAddressEncodeAddress(t *testing.T) {
} }
func TestBcashAddressAreEqual(t *testing.T) { func TestBcashAddressAreEqual(t *testing.T) {
addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy) addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", Legacy)
if err != nil { if err != nil {
t.Errorf("newBCashAddress() error = %v", err) t.Errorf("newBCashAddress() error = %v", err)
return return
} }
addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr) addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", CashAddr)
if err != nil { if err != nil {
t.Errorf("newBCashAddress() error = %v", err) t.Errorf("newBCashAddress() error = %v", err)
return return
@ -60,12 +60,12 @@ func TestBcashAddressAreEqual(t *testing.T) {
} }
func TestBcashAddressInSlice(t *testing.T) { func TestBcashAddressInSlice(t *testing.T) {
addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy) addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", Legacy)
if err != nil { if err != nil {
t.Errorf("newBCashAddress() error = %v", err) t.Errorf("newBCashAddress() error = %v", err)
return return
} }
addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr) addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", CashAddr)
if err != nil { if err != nil {
t.Errorf("newBCashAddress() error = %v", err) t.Errorf("newBCashAddress() error = %v", err)
return return
@ -128,12 +128,12 @@ func init() {
addr1, addr2, addr3 bchain.Address addr1, addr2, addr3 bchain.Address
err error err error
) )
addr1, err = newBCashAddress("3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", GetChainParams("main"), Legacy) addr1, err = newBCashAddress("3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", Legacy)
if err == nil { if err == nil {
addr2, err = newBCashAddress("2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", GetChainParams("test"), Legacy) addr2, err = newBCashAddress("2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", Legacy)
} }
if err == nil { if err == nil {
addr3, err = newBCashAddress("2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", GetChainParams("test"), Legacy) addr3, err = newBCashAddress("2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", Legacy)
} }
if err != nil { if err != nil {
panic(err) panic(err)
@ -161,7 +161,7 @@ func init() {
ScriptPubKey: bchain.ScriptPubKey{ ScriptPubKey: bchain.ScriptPubKey{
Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87", Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87",
Addresses: []string{ Addresses: []string{
"3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", "bitcoincash:pps5f4tu3tl5sjfvnhaeznsjpvst44eddugfcnqpy9",
}, },
}, },
Address: addr1, Address: addr1,
@ -191,7 +191,7 @@ func init() {
ScriptPubKey: bchain.ScriptPubKey{ ScriptPubKey: bchain.ScriptPubKey{
Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887", Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887",
Addresses: []string{ Addresses: []string{
"2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", "bchtest:prxkdrtcrm8xqrh6fvjqfhy3l5nt3w9wmq9fmsvkmz",
}, },
}, },
Address: addr2, Address: addr2,
@ -202,7 +202,7 @@ func init() {
ScriptPubKey: bchain.ScriptPubKey{ ScriptPubKey: bchain.ScriptPubKey{
Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87", Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87",
Addresses: []string{ Addresses: []string{
"2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", "bchtest:pqjxv4dah42v0erh6r4zxa0gdcxm9w8cpg0qw8tqf6",
}, },
}, },
Address: addr3, Address: addr3,

View File

@ -14,10 +14,14 @@ import (
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
) )
// OutputScriptToAddressesFunc converts ScriptPubKey to bitcoin addresses
type OutputScriptToAddressesFunc func(script []byte, params *chaincfg.Params) ([]string, error)
// BitcoinParser handle // BitcoinParser handle
type BitcoinParser struct { type BitcoinParser struct {
*bchain.BaseParser *bchain.BaseParser
Params *chaincfg.Params Params *chaincfg.Params
OutputScriptToAddresses OutputScriptToAddressesFunc
} }
// NewBitcoinParser returns new BitcoinParser instance // NewBitcoinParser returns new BitcoinParser instance
@ -28,6 +32,7 @@ func NewBitcoinParser(params *chaincfg.Params, c *Configuration) *BitcoinParser
BlockAddressesToKeep: c.BlockAddressesToKeep, BlockAddressesToKeep: c.BlockAddressesToKeep,
}, },
params, params,
outputScriptToAddresses,
} }
} }
@ -67,9 +72,9 @@ func (p *BitcoinParser) AddressToOutputScript(address string) ([]byte, error) {
return script, nil return script, nil
} }
// OutputScriptToAddresses converts ScriptPubKey to bitcoin addresses // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
func (p *BitcoinParser) OutputScriptToAddresses(script []byte) ([]string, error) { func outputScriptToAddresses(script []byte, params *chaincfg.Params) ([]string, error) {
_, addresses, _, err := txscript.ExtractPkScriptAddrs(script, p.Params) _, addresses, _, err := txscript.ExtractPkScriptAddrs(script, params)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -105,7 +110,7 @@ func (p *BitcoinParser) txFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.T
for i, out := range t.TxOut { for i, out := range t.TxOut {
addrs := []string{} addrs := []string{}
if parseAddresses { if parseAddresses {
addrs, _ = p.OutputScriptToAddresses(out.PkScript) addrs, _ = p.OutputScriptToAddresses(out.PkScript, p.Params)
} }
s := bchain.ScriptPubKey{ s := bchain.ScriptPubKey{
Hex: hex.EncodeToString(out.PkScript), Hex: hex.EncodeToString(out.PkScript),

View File

@ -94,17 +94,16 @@ func TestOutputScriptToAddresses(t *testing.T) {
wantErr: false, wantErr: false,
}, },
} }
parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.args.script) b, _ := hex.DecodeString(tt.args.script)
got, err := parser.OutputScriptToAddresses(b) got, err := outputScriptToAddresses(b, GetChainParams("main"))
if (err != nil) != tt.wantErr { 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 return
} }
if !reflect.DeepEqual(got, tt.want) { if !reflect.DeepEqual(got, tt.want) {
t.Errorf("OutputScriptToAddresses() = %v, want %v", got, tt.want) t.Errorf("outputScriptToAddresses() = %v, want %v", got, tt.want)
} }
}) })
} }

View File

@ -156,7 +156,6 @@ type BlockChainParser interface {
GetAddrIDFromAddress(address string) ([]byte, error) GetAddrIDFromAddress(address string) ([]byte, error)
// address to output script conversions // address to output script conversions
AddressToOutputScript(address string) ([]byte, error) AddressToOutputScript(address string) ([]byte, error)
OutputScriptToAddresses(script []byte) ([]string, error)
// transactions // transactions
PackedTxidLen() int PackedTxidLen() int
PackTxid(txid string) ([]byte, error) PackTxid(txid string) ([]byte, error)