diff --git a/bchain/baseparser.go b/bchain/baseparser.go index 1b831b44..ba8bfb1a 100644 --- a/bchain/baseparser.go +++ b/bchain/baseparser.go @@ -2,6 +2,7 @@ package bchain import ( "encoding/hex" + "fmt" "github.com/gogo/protobuf/proto" "github.com/juju/errors" @@ -149,6 +150,9 @@ func (p *BaseParser) UnpackTx(buf []byte) (*Tx, uint32, error) { }, Value: pto.Value, } + if len(pto.Addresses) == 1 { + vout[i].Address = NewBaseAddress(pto.Addresses[0]) + } } tx := Tx{ Blocktime: int64(pt.Blocktime), @@ -161,3 +165,22 @@ func (p *BaseParser) UnpackTx(buf []byte) (*Tx, uint32, error) { } return &tx, pt.Height, nil } + +type baseAddress struct { + addr string +} + +func NewBaseAddress(addr string) Address { + return &baseAddress{addr: addr} +} + +func (a baseAddress) String() string { + return a.addr +} + +func (a baseAddress) EncodeAddress(format uint8) (string, error) { + if format != 0 { + return "", fmt.Errorf("Unknown address format: %d", format) + } + return a.addr, nil +} diff --git a/bchain/coins/bch/bcashparser.go b/bchain/coins/bch/bcashparser.go index 3df5f65e..8eb94292 100644 --- a/bchain/coins/bch/bcashparser.go +++ b/bchain/coins/bch/bcashparser.go @@ -1,13 +1,16 @@ package bch import ( + "blockbook/bchain" "blockbook/bchain/coins/btc" + "fmt" "strings" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcutil" "github.com/cpacia/bchutil" + "github.com/golang/glog" ) var prefixes []string @@ -51,7 +54,7 @@ func (p *BCashParser) GetAddrIDFromAddress(address string) ([]byte, error) { // AddressToOutputScript converts bitcoin address to ScriptPubKey func (p *BCashParser) AddressToOutputScript(address string) ([]byte, error) { - if strings.Contains(address, ":") { + if isCashAddr(address) { da, err := bchutil.DecodeAddress(address, p.Params) if err != nil { return nil, err @@ -73,3 +76,75 @@ func (p *BCashParser) AddressToOutputScript(address string) ([]byte, error) { return script, nil } } + +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 + } + } + return false +} + +func (p *BCashParser) UnpackTx(buf []byte) (tx *bchain.Tx, height uint32, err error) { + tx, height, err = p.BitcoinParser.UnpackTx(buf) + + for i, vout := range tx.Vout { + if len(vout.ScriptPubKey.Addresses) == 1 { + tx.Vout[i].Address = &bcashAddress{ + addr: vout.ScriptPubKey.Addresses[0], + net: p.Params, + } + } + } + + return +} + +type bcashAddress struct { + addr string + net *chaincfg.Params +} + +func (a *bcashAddress) String() string { + return a.addr +} + +type AddressFormat = uint8 + +const ( + LegacyAddress AddressFormat = iota + CashAddress +) + +func (a *bcashAddress) EncodeAddress(format AddressFormat) (string, error) { + switch format { + case LegacyAddress: + return a.String(), nil + case CashAddress: + da, err := btcutil.DecodeAddress(a.addr, a.net) + if err != nil { + return "", err + } + var ca btcutil.Address + switch da := da.(type) { + case *btcutil.AddressPubKeyHash: + ca, err = bchutil.NewCashAddressPubKeyHash(da.Hash160()[:], a.net) + case *btcutil.AddressScriptHash: + ca, err = bchutil.NewCashAddressScriptHash(da.Hash160()[:], a.net) + default: + err = fmt.Errorf("Unknown address type: %T", da) + } + if err != nil { + return "", err + } + return ca.String(), nil + + default: + return "", fmt.Errorf("Unknown address format: %d", format) + } +} diff --git a/bchain/coins/btc/bitcoinparser.go b/bchain/coins/btc/bitcoinparser.go index 0f1578ae..0c1f2fe7 100644 --- a/bchain/coins/btc/bitcoinparser.go +++ b/bchain/coins/btc/bitcoinparser.go @@ -169,5 +169,12 @@ func (p *BitcoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { return nil, 0, err } tx.Blocktime = bt + + for i, vout := range tx.Vout { + if len(vout.ScriptPubKey.Addresses) == 1 { + tx.Vout[i].Address = bchain.NewBaseAddress(vout.ScriptPubKey.Addresses[0]) + } + } + return tx, height, nil } diff --git a/bchain/types.go b/bchain/types.go index 8e2a3d1b..59ce276e 100644 --- a/bchain/types.go +++ b/bchain/types.go @@ -37,10 +37,16 @@ type ScriptPubKey struct { Addresses []string `json:"addresses,omitempty"` } +type Address interface { + String() string + EncodeAddress(format uint8) (string, error) +} + type Vout struct { Value float64 `json:"value"` N uint32 `json:"n"` ScriptPubKey ScriptPubKey `json:"scriptPubKey"` + Address Address } // Tx is blockchain transaction