Upgraded BCash address decoding/encoding
parent
ea3cfd2d6a
commit
79ba6abadd
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue