Upgraded BCash address decoding/encoding

pull/7/head
Jakub Matys 2018-05-29 15:03:25 +02:00
parent ea3cfd2d6a
commit 79ba6abadd
7 changed files with 97 additions and 173 deletions

14
Gopkg.lock generated
View File

@ -109,6 +109,12 @@
revision = "3247c84500bff8d9fb6d579d800f20b3e091582c"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/mr-tron/base58"
packages = ["base58"]
revision = "c1bdf7c52f59d6685ca597b9955a443ff95eeee6"
[[projects]]
branch = "master"
name = "github.com/pebbe/zmq4"
@ -145,6 +151,12 @@
revision = "feef513b9575b32f84bafa580aad89b011259019"
version = "v1.3.0"
[[projects]]
name = "github.com/schancel/cashaddr-converter"
packages = ["address","baseconv","cashaddress","legacy"]
revision = "0a38f5822f795dc3727b4caacc298e02938d9eb1"
version = "v9"
[[projects]]
branch = "master"
name = "github.com/syndtr/goleveldb"
@ -190,6 +202,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "3a5adb167369a6d82fec8664beb93b7e7c8109b31c9f19ecd8ce1142755d621f"
inputs-digest = "97b5e11b3aa46e6b54a5c3fd7835c49f324f9821a1c641e5682f60ee6716d8c2"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -214,27 +214,16 @@ func (a baseAddress) String() string {
return a.addr
}
func (a baseAddress) EncodeAddress() (string, error) {
return a.addr, nil
func (a baseAddress) AreEqual(addr string) bool {
return a.String() == addr
}
func (a baseAddress) AreEqual(addr string) (bool, error) {
ea, err := a.EncodeAddress()
if err != nil {
return false, err
}
return ea == addr, nil
}
func (a baseAddress) InSlice(addrs []string) (bool, error) {
ea, err := a.EncodeAddress()
if err != nil {
return false, err
}
func (a baseAddress) InSlice(addrs []string) bool {
ea := a.String()
for _, addr := range addrs {
if ea == addr {
return true, nil
return true
}
}
return false, nil
return false
}

View File

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcutil"
"github.com/cpacia/bchutil"
"github.com/schancel/cashaddr-converter/address"
)
type AddressFormat = uint8
@ -28,7 +29,7 @@ type BCashParser struct {
}
// NewBCashParser returns new BCashParser instance
func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) *BCashParser {
func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) (*BCashParser, error) {
var format AddressFormat
switch c.AddressFormat {
case "":
@ -38,11 +39,9 @@ func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) *BCashParser
case "legacy":
format = Legacy
default:
// XXX
e := fmt.Errorf("Unknown address format: %s", c.AddressFormat)
panic(e)
return nil, fmt.Errorf("Unknown address format: %s", c.AddressFormat)
}
return &BCashParser{
p := &BCashParser{
BitcoinParser: &btc.BitcoinParser{
BaseParser: &bchain.BaseParser{
AddressFactory: func(addr string) (bchain.Address, error) { return newBCashAddress(addr, params, format) },
@ -52,6 +51,7 @@ func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) *BCashParser
},
AddressFormat: format,
}
return p, nil
}
// GetChainParams contains network parameters for the main Bitcoin Cash network,
@ -137,96 +137,55 @@ func (p *BCashParser) UnpackTx(buf []byte) (tx *bchain.Tx, height uint32, err er
}
type bcashAddress struct {
addr btcutil.Address
net *chaincfg.Params
format AddressFormat
addr string
}
func newBCashAddress(addr string, net *chaincfg.Params, format AddressFormat) (*bcashAddress, error) {
var (
da btcutil.Address
err error
)
if isCashAddr(addr) {
// for cashaddr we need to convert it to the legacy form (i.e. to btcutil's Address)
// because bchutil doesn't allow later conversions
da, err = bchutil.DecodeAddress(addr, net)
if err != nil {
return nil, err
}
switch ca := da.(type) {
case *bchutil.CashAddressPubKeyHash:
da, err = btcutil.NewAddressPubKeyHash(ca.Hash160()[:], net)
case *bchutil.CashAddressScriptHash:
da, err = btcutil.NewAddressScriptHash(ca.Hash160()[:], net)
default:
err = fmt.Errorf("Unknown address type: %T", da)
}
if err != nil {
return nil, err
}
} else {
da, err = btcutil.DecodeAddress(addr, net)
if err != nil {
return nil, err
}
da, err := address.NewFromString(addr)
if err != nil {
return nil, err
}
var ea string
switch format {
case Legacy, CashAddr:
case CashAddr:
if a, err := da.CashAddress(); err != nil {
return nil, err
} else {
ea, err = a.Encode()
if err != nil {
return nil, err
}
}
case Legacy:
if a, err := da.Legacy(); err != nil {
return nil, err
} else {
ea, err = a.Encode()
if err != nil {
return nil, err
}
}
default:
return nil, fmt.Errorf("Unknown address format: %d", format)
}
return &bcashAddress{addr: da, net: net, format: format}, nil
return &bcashAddress{addr: ea}, nil
}
func (a *bcashAddress) String() string {
return a.addr.String()
return a.addr
}
func (a *bcashAddress) EncodeAddress() (string, error) {
switch a.format {
case Legacy:
return a.String(), nil
case CashAddr:
var (
ca btcutil.Address
err error
)
switch da := a.addr.(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", a.format)
}
func (a *bcashAddress) AreEqual(addr string) bool {
return a.String() == addr
}
func (a *bcashAddress) AreEqual(addr string) (bool, error) {
ea, err := a.EncodeAddress()
if err != nil {
return false, err
}
return ea == addr, nil
}
func (a *bcashAddress) InSlice(addrs []string) (bool, error) {
ea, err := a.EncodeAddress()
if err != nil {
return false, err
}
func (a *bcashAddress) InSlice(addrs []string) bool {
ea := a.String()
for _, addr := range addrs {
if ea == addr {
return true, nil
return true
}
}
return false, nil
return false
}

View File

@ -15,26 +15,18 @@ func TestBcashAddressEncodeAddress(t *testing.T) {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got1, err := addr1.EncodeAddress()
if err != nil {
t.Errorf("EncodeAddress() error = %v", err)
return
}
got1 := addr1.String()
if got1 != "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji" {
t.Errorf("EncodeAddress() got1 = %v, want %v", got1, "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji")
t.Errorf("String() got1 = %v, want %v", got1, "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji")
}
addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr)
if err != nil {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got2, err := addr2.EncodeAddress()
if err != nil {
t.Errorf("EncodeAddress() error = %v", err)
return
}
got2 := addr2.String()
if got2 != "bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf" {
t.Errorf("EncodeAddress() got2 = %v, want %v", got2, "bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf")
t.Errorf("String() got2 = %v, want %v", got2, "bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf")
}
}
@ -49,35 +41,19 @@ func TestBcashAddressAreEqual(t *testing.T) {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got1, err := addr1.AreEqual("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji")
if err != nil {
t.Errorf("AreEqual() error = %v", err)
return
}
got1 := addr1.AreEqual("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji")
if got1 != true {
t.Errorf("AreEqual() got1 = %v, want %v", got1, true)
}
got2, err := addr2.AreEqual("bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf")
if err != nil {
t.Errorf("AreEqual() error = %v", err)
return
}
got2 := addr2.AreEqual("bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf")
if got2 != true {
t.Errorf("AreEqual() got2 = %v, want %v", got2, true)
}
got3, err := addr1.AreEqual("1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w")
if err != nil {
t.Errorf("AreEqual() error = %v", err)
return
}
got3 := addr1.AreEqual("1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w")
if got3 != false {
t.Errorf("AreEqual() got3 = %v, want %v", got3, false)
}
got4, err := addr2.AreEqual("bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch")
if err != nil {
t.Errorf("AreEqual() error = %v", err)
return
}
got4 := addr2.AreEqual("bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch")
if got4 != false {
t.Errorf("AreEqual() got4 = %v, want %v", got4, false)
}
@ -94,42 +70,30 @@ func TestBcashAddressInSlice(t *testing.T) {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got1, err := addr1.InSlice([]string{"13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", "1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w"})
if err != nil {
t.Errorf("InSlice() error = %v", err)
return
}
got1 := addr1.InSlice([]string{"13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", "1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w"})
if got1 != true {
t.Errorf("InSlice() got1 = %v, want %v", got1, true)
}
got2, err := addr2.InSlice([]string{"bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch", "bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf"})
if err != nil {
t.Errorf("InSlice() error = %v", err)
return
}
got2 := addr2.InSlice([]string{"bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch", "bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf"})
if got2 != true {
t.Errorf("InSlice() got2 = %v, want %v", got2, true)
}
got3, err := addr1.InSlice([]string{"1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w", "1E6Np6dUPYpBSdLMLuwBF8sRQ3cngdaRRY"})
if err != nil {
t.Errorf("InSlice() error = %v", err)
return
}
got3 := addr1.InSlice([]string{"1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w", "1E6Np6dUPYpBSdLMLuwBF8sRQ3cngdaRRY"})
if got3 != false {
t.Errorf("InSlice() got3 = %v, want %v", got3, false)
}
got4, err := addr2.InSlice([]string{"bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch", "bitcoincash:qz8emmpenqgeg7et8xsz8prvhy6cqcalyyjcamt7e9"})
if err != nil {
t.Errorf("InSlice() error = %v", err)
return
}
got4 := addr2.InSlice([]string{"bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch", "bitcoincash:qz8emmpenqgeg7et8xsz8prvhy6cqcalyyjcamt7e9"})
if got4 != false {
t.Errorf("InSlice() got4 = %v, want %v", got4, false)
}
}
func TestAddressToOutputScript(t *testing.T) {
parser := NewBCashParser(GetChainParams("test"), &btc.Configuration{})
parser, err := NewBCashParser(GetChainParams("test"), &btc.Configuration{AddressFormat: "legacy"})
if err != nil {
t.Errorf("NewBCashParser() error = %v", err)
return
}
want, err := hex.DecodeString("76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac")
if err != nil {
panic(err)
@ -248,6 +212,17 @@ func init() {
}
func Test_UnpackTx(t *testing.T) {
parser1, err := NewBCashParser(GetChainParams("main"), &btc.Configuration{AddressFormat: "legacy"})
if err != nil {
t.Errorf("NewBCashParser() error = %v", err)
return
}
parser2, err := NewBCashParser(GetChainParams("test"), &btc.Configuration{AddressFormat: "legacy"})
if err != nil {
t.Errorf("NewBCashParser() error = %v", err)
return
}
type args struct {
packedTx string
parser *BCashParser
@ -263,7 +238,7 @@ func Test_UnpackTx(t *testing.T) {
name: "btc-1",
args: args{
packedTx: testTxPacked1,
parser: NewBCashParser(GetChainParams("main"), &btc.Configuration{AddressFormat: "legacy"}),
parser: parser1,
},
want: &testTx1,
want1: 123456,
@ -273,7 +248,7 @@ func Test_UnpackTx(t *testing.T) {
name: "testnet-1",
args: args{
packedTx: testTxPacked2,
parser: NewBCashParser(GetChainParams("test"), &btc.Configuration{AddressFormat: "legacy"}),
parser: parser2,
},
want: &testTx2,
want1: 510234,

View File

@ -32,7 +32,6 @@ func NewBCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
// Initialize initializes BCashRPC instance.
func (b *BCashRPC) Initialize() error {
chainName, err := b.GetChainInfoAndInitializeMempool(b)
if err != nil {
return err
@ -41,7 +40,11 @@ func (b *BCashRPC) Initialize() error {
params := GetChainParams(chainName)
// always create parser
b.Parser = NewBCashParser(params, b.ChainConfig)
b.Parser, err = NewBCashParser(params, b.ChainConfig)
if err != nil {
return err
}
// parameters for getInfo request
if params.Net == bchutil.MainnetMagic {

View File

@ -43,9 +43,8 @@ type ScriptPubKey struct {
type Address interface {
String() string
EncodeAddress() (string, error)
AreEqual(addr string) (bool, error)
InSlice(addrs []string) (bool, error)
AreEqual(addr string) bool
InSlice(addrs []string) bool
}
type Vout struct {

View File

@ -478,16 +478,9 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r
Script: &aoh,
}
if vout.Address != nil {
a, err := vout.Address.EncodeAddress()
if err != nil {
return res, err
}
a := vout.Address.String()
ao.Address = &a
found, err := vout.Address.InSlice(addr)
if err != nil {
return res, err
}
if found {
if vout.Address.InSlice(addr) {
hi, ok := ads[a]
if ok {
hi.OutputIndexes = append(hi.OutputIndexes, int(vout.N))
@ -735,10 +728,7 @@ func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetai
if len(otx.Vout) > int(vin.Vout) {
vout := otx.Vout[vin.Vout]
if vout.Address != nil {
a, err := vout.Address.EncodeAddress()
if err != nil {
return res, err
}
a := vout.Address.String()
ai.Address = &a
}
ai.Satoshis = int64(vout.Value*1E8 + 0.5)
@ -753,10 +743,7 @@ func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetai
Script: &aos,
}
if vout.Address != nil {
a, err := vout.Address.EncodeAddress()
if err != nil {
return res, err
}
a := vout.Address.String()
ao.Address = &a
}
ho = append(ho, ao)