Fix decred's xpub decoding (#249)
* Add the decred xpub decoding implementation * Fix the address decoding * Resolve the extended public key path * Add tests for DeriveAddressDescriptors and DeriveAddressDescriptorsFromTo methods * Add TestDerivationBasePath * Add tests for pack and unpack methodspull/268/head
parent
d6375a19dd
commit
5ea4bbded6
|
@ -78,8 +78,8 @@
|
|||
[[projects]]
|
||||
name = "github.com/decred/dcrd"
|
||||
packages = ["chaincfg","chaincfg/chainec","chaincfg/chainhash","dcrec","dcrec/edwards","dcrec/secp256k1","dcrec/secp256k1/schnorr","dcrjson","dcrutil","txscript","wire"]
|
||||
revision = "0fe564967f03160b9dbe0a147420d8aa13371d12"
|
||||
version = "v1.3.0"
|
||||
revision = "e3e8c47c68b010dbddeb783ebad32a3a4993dd71"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/decred/slog"
|
||||
|
|
|
@ -2,18 +2,24 @@ package dcr
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"blockbook/bchain"
|
||||
"blockbook/bchain/coins/btc"
|
||||
"blockbook/bchain/coins/utils"
|
||||
|
||||
cfg "github.com/decred/dcrd/chaincfg"
|
||||
"github.com/decred/dcrd/chaincfg/chainhash"
|
||||
"github.com/decred/dcrd/hdkeychain"
|
||||
"github.com/decred/dcrd/txscript"
|
||||
"github.com/juju/errors"
|
||||
"github.com/martinboehm/btcd/wire"
|
||||
"github.com/martinboehm/btcutil/base58"
|
||||
"github.com/martinboehm/btcutil/chaincfg"
|
||||
)
|
||||
|
||||
|
@ -47,14 +53,23 @@ func init() {
|
|||
type DecredParser struct {
|
||||
*btc.BitcoinParser
|
||||
baseParser *bchain.BaseParser
|
||||
netConfig *cfg.Params
|
||||
}
|
||||
|
||||
// NewDecredParser returns new DecredParser instance
|
||||
func NewDecredParser(params *chaincfg.Params, c *btc.Configuration) *DecredParser {
|
||||
return &DecredParser{
|
||||
d := &DecredParser{
|
||||
BitcoinParser: btc.NewBitcoinParser(params, c),
|
||||
baseParser: &bchain.BaseParser{},
|
||||
}
|
||||
|
||||
switch d.BitcoinParser.Params.Name {
|
||||
case "testnet3":
|
||||
d.netConfig = &cfg.TestNet3Params
|
||||
default:
|
||||
d.netConfig = &cfg.MainNetParams
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// GetChainParams contains network parameters for the main Decred network,
|
||||
|
@ -168,30 +183,25 @@ func (p *DecredParser) ParseTxFromJson(jsonTx json.RawMessage) (*bchain.Tx, erro
|
|||
return tx, nil
|
||||
}
|
||||
|
||||
// GetAddrDescForUnknownInput returns nil AddressDescriptor
|
||||
// GetAddrDescForUnknownInput returns nil AddressDescriptor.
|
||||
func (p *DecredParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAddrDescFromAddress returns internal address representation of a given address.
|
||||
func (p *DecredParser) GetAddrDescFromAddress(address string) (bchain.AddressDescriptor, error) {
|
||||
addressByte := []byte(address)
|
||||
return bchain.AddressDescriptor(addressByte), nil
|
||||
}
|
||||
|
||||
// GetAddrDescFromVout returns internal address representation of a given transaction output.
|
||||
func (p *DecredParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressDescriptor, error) {
|
||||
script, err := hex.DecodeString(output.ScriptPubKey.Hex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var params cfg.Params
|
||||
if p.Params.Name == "mainnet" {
|
||||
params = cfg.MainNetParams
|
||||
} else {
|
||||
params = cfg.TestNet3Params
|
||||
}
|
||||
|
||||
scriptClass, addresses, _, err := txscript.ExtractPkScriptAddrs(txscript.DefaultScriptVersion, script, ¶ms)
|
||||
scriptClass, addresses, _, err := txscript.ExtractPkScriptAddrs(txscript.DefaultScriptVersion, script, p.netConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -206,17 +216,15 @@ func (p *DecredParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressD
|
|||
for i := range addresses {
|
||||
addressByte = append(addressByte, addresses[i].String()...)
|
||||
}
|
||||
|
||||
return bchain.AddressDescriptor(addressByte), nil
|
||||
}
|
||||
|
||||
// GetAddressesFromAddrDesc returns addresses obtained from the internal address representation
|
||||
func (p *DecredParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) {
|
||||
var addrs []string
|
||||
|
||||
if addrDesc != nil {
|
||||
addrs = append(addrs, string(addrDesc))
|
||||
}
|
||||
|
||||
return addrs, true, nil
|
||||
}
|
||||
|
||||
|
@ -229,3 +237,119 @@ func (p *DecredParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]
|
|||
func (p *DecredParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
||||
return p.baseParser.UnpackTx(buf)
|
||||
}
|
||||
|
||||
func (p *DecredParser) addrDescFromExtKey(extKey *hdkeychain.ExtendedKey) (bchain.AddressDescriptor, error) {
|
||||
var addr, err = extKey.Address(p.netConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.GetAddrDescFromAddress(addr.String())
|
||||
}
|
||||
|
||||
// DeriveAddressDescriptors derives address descriptors from given xpub for
|
||||
// listed indexes
|
||||
func (p *DecredParser) DeriveAddressDescriptors(xpub string, change uint32,
|
||||
indexes []uint32) ([]bchain.AddressDescriptor, error) {
|
||||
extKey, err := hdkeychain.NewKeyFromString(xpub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
changeExtKey, err := extKey.Child(change)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ad := make([]bchain.AddressDescriptor, len(indexes))
|
||||
for i, index := range indexes {
|
||||
indexExtKey, err := changeExtKey.Child(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ad[i], err = p.addrDescFromExtKey(indexExtKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return ad, nil
|
||||
}
|
||||
|
||||
// DeriveAddressDescriptorsFromTo derives address descriptors from given xpub for
|
||||
// addresses in index range
|
||||
func (p *DecredParser) DeriveAddressDescriptorsFromTo(xpub string, change uint32,
|
||||
fromIndex uint32, toIndex uint32) ([]bchain.AddressDescriptor, error) {
|
||||
if toIndex <= fromIndex {
|
||||
return nil, errors.New("toIndex<=fromIndex")
|
||||
}
|
||||
extKey, err := hdkeychain.NewKeyFromString(xpub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changeExtKey, err := extKey.Child(change)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ad := make([]bchain.AddressDescriptor, toIndex-fromIndex)
|
||||
for index := fromIndex; index < toIndex; index++ {
|
||||
indexExtKey, err := changeExtKey.Child(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ad[index-fromIndex], err = p.addrDescFromExtKey(indexExtKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return ad, nil
|
||||
}
|
||||
|
||||
// DerivationBasePath returns base path of xpub which whose full format is
|
||||
// m/44'/<coin type>'/<account>'/<branch>/<address index>. This function only
|
||||
// returns a path up to m/44'/<coin type>'/<account>'/ whereby the rest of the
|
||||
// other details (<branch>/<address index>) are populated automatically.
|
||||
func (p *DecredParser) DerivationBasePath(xpub string) (string, error) {
|
||||
var c string
|
||||
cn, depth, err := p.decodeXpub(xpub)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if cn >= hdkeychain.HardenedKeyStart {
|
||||
cn -= hdkeychain.HardenedKeyStart
|
||||
c = "'"
|
||||
}
|
||||
|
||||
c = strconv.Itoa(int(cn)) + c
|
||||
if depth != 3 {
|
||||
return "unknown/" + c, nil
|
||||
}
|
||||
|
||||
return "m/44'/" + strconv.Itoa(int(p.Slip44)) + "'/" + c, nil
|
||||
}
|
||||
|
||||
func (p *DecredParser) decodeXpub(xpub string) (childNum uint32, depth uint16, err error) {
|
||||
decoded := base58.Decode(xpub)
|
||||
|
||||
// serializedKeyLen is the length of a serialized public or private
|
||||
// extended key. It consists of 4 bytes version, 1 byte depth, 4 bytes
|
||||
// fingerprint, 4 bytes child number, 32 bytes chain code, and 33 bytes
|
||||
// public/private key data.
|
||||
serializedKeyLen := 4 + 1 + 4 + 4 + 32 + 33 // 78 bytes
|
||||
if len(decoded) != serializedKeyLen+4 {
|
||||
err = errors.New("invalid extended key length")
|
||||
return
|
||||
}
|
||||
|
||||
payload := decoded[:len(decoded)-4]
|
||||
checkSum := decoded[len(decoded)-4:]
|
||||
expectedCheckSum := chainhash.HashB(chainhash.HashB(payload))[:4]
|
||||
if !bytes.Equal(checkSum, expectedCheckSum) {
|
||||
err = errors.New("bad checksum value")
|
||||
return
|
||||
}
|
||||
|
||||
depth = uint16(payload[4:5][0])
|
||||
childNum = binary.BigEndian.Uint32(payload[9:13])
|
||||
return
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
parser *DecredParser
|
||||
testnetParser, mainnetParser *DecredParser
|
||||
|
||||
testTx1 = bchain.Tx{
|
||||
Hex: "01000000012372568fe80d2f9b2ab17226158dd5732d9926dc705371eaf40ab748c9e3d9720200000001ffffffff02644b252d0000000000001976a914a862f83733cc368f386a651e03d844a5bd6116d588acacdf63090000000000001976a91491dc5d18370939b3414603a0729bcb3a38e4ef7688ac000000000000000001e48d893600000000bb3d0000020000006a4730440220378e1442cc17fa7e49184518713eedd30e13e42147e077859557da6ffbbd40c702205f85563c28b6287f9c9110e6864dd18acfd92d85509ea846913c28b6e8a7f940012102bbbd7aadef33f2d2bdd9b0c5ba278815f5d66a6a01d2c019fb73f697662038b5",
|
||||
|
@ -54,6 +54,47 @@ var (
|
|||
}
|
||||
|
||||
testTx2 = bchain.Tx{
|
||||
Hex: "0100000001193c189c71dff482b70ccb10ec9cf0ea3421a7fc51e4c7b0cf59c98a293a2f960200000000ffffffff027c87f00b0000000000001976a91418f10131a859912119c4a8510199f87f0a4cec2488ac9889495f0000000000001976a914631fb783b1e06c3f6e71777e16da6de13450465e88ac0000000000000000015ced3d6b0000000030740000000000006a47304402204e6afc21f6d065b9c082dad81a5f29136320e2b54c6cdf6b8722e4507e1a8d8902203933c5e592df3b0bbb0568f121f48ef6cbfae9cf479a57229742b5780dedc57a012103b89bb443b6ab17724458285b302291b082c59e5a022f273af0f61d47a414a537",
|
||||
Txid: "7058766ffef2e9cee61ee4b7604a39bc91c3000cb951c4f93f3307f6e0bf4def",
|
||||
Blocktime: 1463843967,
|
||||
Time: 1463843967,
|
||||
LockTime: 0,
|
||||
Version: 1,
|
||||
Vin: []bchain.Vin{
|
||||
{
|
||||
Txid: "962f3a298ac959cfb0c7e451fca72134eaf09cec10cb0cb782f4df719c183c19",
|
||||
Vout: 2,
|
||||
Sequence: 4294967295,
|
||||
ScriptSig: bchain.ScriptSig{
|
||||
Hex: "47304402204e6afc21f6d065b9c082dad81a5f29136320e2b54c6cdf6b8722e4507e1a8d8902203933c5e592df3b0bbb0568f121f48ef6cbfae9cf479a57229742b5780dedc57a012103b89bb443b6ab17724458285b302291b082c59e5a022f273af0f61d47a414a537",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vout: []bchain.Vout{
|
||||
{
|
||||
ValueSat: *big.NewInt(200312700),
|
||||
N: 0,
|
||||
ScriptPubKey: bchain.ScriptPubKey{
|
||||
Hex: "76a91418f10131a859912119c4a8510199f87f0a4cec2488ac",
|
||||
Addresses: []string{
|
||||
"DsTEnRLDEjQNeQ4A47fdS2pqtaFrGNzkqNa",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ValueSat: *big.NewInt(1598654872),
|
||||
N: 1,
|
||||
ScriptPubKey: bchain.ScriptPubKey{
|
||||
Hex: "76a914631fb783b1e06c3f6e71777e16da6de13450465e88ac",
|
||||
Addresses: []string{
|
||||
"Dsa12P9VnCd55hTnUXpvGgFKSeGkFkzRvYb",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testTx3 = bchain.Tx{
|
||||
Hex: "0100000001c56d80756eaa7fc6e3542b29f596c60a9bcc959cf04d5f6e6b12749e241ece290200000001ffffffff02cf20b42d0000000000001976a9140799daa3cd36b44def220886802eb99e10c4a7c488ac0c25c7070000000000001976a9140b102deb3314213164cb6322211225365658407e88ac000000000000000001afa87b3500000000e33d0000000000006a47304402201ff342e5aa55b6030171f85729221ca0b81938826cc09449b77752e6e3b615be0220281e160b618e57326b95a0e0c3ac7a513bd041aba63cbace2f71919e111cfdba01210290a8de6665c8caac2bb8ca1aabd3dc09a334f997f97bd894772b1e51cab003d9",
|
||||
Blocktime: 1535638326,
|
||||
Time: 1535638326,
|
||||
|
@ -93,7 +134,8 @@ var (
|
|||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
parser = NewDecredParser(GetChainParams("testnet3"), &btc.Configuration{})
|
||||
testnetParser = NewDecredParser(GetChainParams("testnet3"), &btc.Configuration{Slip44: 1})
|
||||
mainnetParser = NewDecredParser(GetChainParams("mainnet"), &btc.Configuration{Slip44: 42})
|
||||
exitCode := m.Run()
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
@ -130,7 +172,7 @@ func TestGetAddrDescFromAddress(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parser.GetAddrDescFromAddress(tt.args.address)
|
||||
got, err := testnetParser.GetAddrDescFromAddress(tt.args.address)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
@ -174,7 +216,7 @@ func TestGetAddrDescFromVout(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parser.GetAddrDescFromVout(&tt.args.vout)
|
||||
got, err := testnetParser.GetAddrDescFromVout(&tt.args.vout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("GetAddrDescFromVout() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
@ -223,7 +265,7 @@ func TestGetAddressesFromAddrDesc(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
b, _ := hex.DecodeString(tt.args.script)
|
||||
got, got2, err := parser.GetAddressesFromAddrDesc(b)
|
||||
got, got2, err := testnetParser.GetAddressesFromAddrDesc(b)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("GetAddressesFromAddrDesc() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
@ -236,3 +278,259 @@ func TestGetAddressesFromAddrDesc(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveAddressDescriptors(t *testing.T) {
|
||||
type args struct {
|
||||
xpub string
|
||||
change uint32
|
||||
indexes []uint32
|
||||
parser *DecredParser
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "m/44'/42'/0'",
|
||||
args: args{
|
||||
xpub: "dpubZFYFpu8cZxwrApmtot59LZLChk5JcdB8xCxVQ4pcsTig4fscH3EfAkhxcKKhXBQH6SGyYs2VDidoomA5qukTWMaHDkBsAtnpodAHm61ozbD",
|
||||
change: 0,
|
||||
indexes: []uint32{0, 5},
|
||||
parser: mainnetParser,
|
||||
},
|
||||
want: []string{"DsUPx4NgAJzUQFRXnn2XZnWwEeQkQpwhqFD", "DsaT4kaGCeJU1Fef721J2DNt8UgcrmE2UsD"},
|
||||
},
|
||||
{
|
||||
name: "m/44'/42'/1'",
|
||||
args: args{
|
||||
xpub: "dpubZFYFpu8cZxwrESo75eazNjVHtC4nWJqL5aXxExZHKnyvZxKirkpypbgeJhVzhTdfnK2986DLjich4JQqcSaSyxu5KSoZ25KJ67j4mQJ9iqx",
|
||||
change: 0,
|
||||
indexes: []uint32{0, 5},
|
||||
parser: mainnetParser,
|
||||
},
|
||||
want: []string{"DsX5px9k9XZKFNP2Z9kyZBbfHgecm1ftNz6", "Dshjbo35CSWwNo7xMgG7UM8AWykwEjJ5DCP"},
|
||||
},
|
||||
{
|
||||
name: "m/44'/1'/0'",
|
||||
args: args{
|
||||
xpub: "tpubVossdTiJthe9xZZ5rz47szxN6ncpLJ4XmtJS26hKciDUPtboikdwHKZPWfo4FWYuLRZ6MNkLjyPRKhxqjStBTV2BE1LCULznpqsFakkPfPr",
|
||||
change: 0,
|
||||
indexes: []uint32{0, 2},
|
||||
parser: testnetParser,
|
||||
},
|
||||
want: []string{"TsboBwzpaH831s9J63XDcDx5GbKLcwv9ujo", "TsXrNt9nP3kBUM2Wr3rQGoPrpL7RMMSJyJH"},
|
||||
},
|
||||
{
|
||||
name: "m/44'/1'/1'",
|
||||
args: args{
|
||||
xpub: "tpubVossdTiJtheA1fQniKn9EN1JE1Eq1kBofaq2KwywrvuNhAk1KsEM7J2r8anhMJUmmcn9Wmoh73EctpW7Vxs3gS8cbF7N3m4zVjzuyvBj3qC",
|
||||
change: 0,
|
||||
indexes: []uint32{0, 3},
|
||||
parser: testnetParser,
|
||||
},
|
||||
want: []string{"TsndBjzcwZVjoZEuqYKwiMbCJH9QpkEekg4", "TsbrkVdFciW3Lfh1W8qjwRY9uSbdiBmY4VP"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.args.parser.DeriveAddressDescriptors(tt.args.xpub, tt.args.change, tt.args.indexes)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
gotAddresses := make([]string, len(got))
|
||||
for i, ad := range got {
|
||||
aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad)
|
||||
if err != nil || len(aa) != 1 {
|
||||
t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err)
|
||||
return
|
||||
}
|
||||
gotAddresses[i] = aa[0]
|
||||
}
|
||||
if !reflect.DeepEqual(gotAddresses, tt.want) {
|
||||
t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
|
||||
type args struct {
|
||||
xpub string
|
||||
change uint32
|
||||
fromIndex uint32
|
||||
toIndex uint32
|
||||
parser *DecredParser
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "m/44'/42'/2'",
|
||||
args: args{
|
||||
xpub: "dpubZFYFpu8cZxwrGnWbdHmvsAcTaMve4W9EAUiSHzXp1c5hQvfeWgk7LxsE5LqopwfxV62CoB51fxw97YaNpdA3tdo4GHbLxtUzRmYcUtVPYUi",
|
||||
change: 0,
|
||||
fromIndex: 0,
|
||||
toIndex: 1,
|
||||
parser: mainnetParser,
|
||||
},
|
||||
want: []string{"Dshtd1N7pKw814wgWXUq5qFVC5ENQ9oSGK7"},
|
||||
},
|
||||
{
|
||||
name: "m/44'/42'/1'",
|
||||
args: args{
|
||||
xpub: "dpubZFYFpu8cZxwrESo75eazNjVHtC4nWJqL5aXxExZHKnyvZxKirkpypbgeJhVzhTdfnK2986DLjich4JQqcSaSyxu5KSoZ25KJ67j4mQJ9iqx",
|
||||
change: 0,
|
||||
fromIndex: 0,
|
||||
toIndex: 1,
|
||||
parser: mainnetParser,
|
||||
},
|
||||
want: []string{"DsX5px9k9XZKFNP2Z9kyZBbfHgecm1ftNz6"},
|
||||
},
|
||||
{
|
||||
name: "m/44'/1'/2'",
|
||||
args: args{
|
||||
xpub: "tpubVossdTiJtheA51AuNQZtqvKUbhM867Von8XBadxX3tRkDm71kyyi6U966jDPEw9RnQjNcQLwxYSnQ9kBjZxrxfmSbByRbz7D1PLjgAPmL42",
|
||||
change: 0,
|
||||
fromIndex: 0,
|
||||
toIndex: 1,
|
||||
parser: testnetParser,
|
||||
},
|
||||
want: []string{"TsSpo87rBG21PLvvbzFk2Ust2Dbyvjfn8pQ"},
|
||||
},
|
||||
{
|
||||
name: "m/44'/1'/1'",
|
||||
args: args{
|
||||
xpub: "tpubVossdTiJtheA1fQniKn9EN1JE1Eq1kBofaq2KwywrvuNhAk1KsEM7J2r8anhMJUmmcn9Wmoh73EctpW7Vxs3gS8cbF7N3m4zVjzuyvBj3qC",
|
||||
change: 0,
|
||||
fromIndex: 0,
|
||||
toIndex: 5,
|
||||
parser: testnetParser,
|
||||
},
|
||||
want: []string{"TsndBjzcwZVjoZEuqYKwiMbCJH9QpkEekg4", "TshWHbnPAVCDARTcCfTEQyL9SzeHxxexX4J", "TspE6pMdC937UHHyfYJpTiKi6vPj5rVnWiG",
|
||||
"TsbrkVdFciW3Lfh1W8qjwRY9uSbdiBmY4VP", "TsagMXjC4Xj6ckPEJh8f1RKHU4cEzTtdVW6"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.args.parser.DeriveAddressDescriptorsFromTo(tt.args.xpub, tt.args.change, tt.args.fromIndex, tt.args.toIndex)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
gotAddresses := make([]string, len(got))
|
||||
for i, ad := range got {
|
||||
aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad)
|
||||
if err != nil || len(aa) != 1 {
|
||||
t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err)
|
||||
return
|
||||
}
|
||||
gotAddresses[i] = aa[0]
|
||||
}
|
||||
if !reflect.DeepEqual(gotAddresses, tt.want) {
|
||||
t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDerivationBasePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
xpub string
|
||||
parser *DecredParser
|
||||
}{
|
||||
{
|
||||
name: "m/44'/42'/2'",
|
||||
xpub: "dpubZFYFpu8cZxwrGnWbdHmvsAcTaMve4W9EAUiSHzXp1c5hQvfeWgk7LxsE5LqopwfxV62CoB51fxw97YaNpdA3tdo4GHbLxtUzRmYcUtVPYUi",
|
||||
parser: mainnetParser,
|
||||
},
|
||||
{
|
||||
name: "m/44'/42'/1'",
|
||||
xpub: "dpubZFYFpu8cZxwrESo75eazNjVHtC4nWJqL5aXxExZHKnyvZxKirkpypbgeJhVzhTdfnK2986DLjich4JQqcSaSyxu5KSoZ25KJ67j4mQJ9iqx",
|
||||
parser: mainnetParser,
|
||||
},
|
||||
{
|
||||
name: "m/44'/1'/2'",
|
||||
xpub: "tpubVossdTiJtheA51AuNQZtqvKUbhM867Von8XBadxX3tRkDm71kyyi6U966jDPEw9RnQjNcQLwxYSnQ9kBjZxrxfmSbByRbz7D1PLjgAPmL42",
|
||||
parser: testnetParser,
|
||||
},
|
||||
{
|
||||
name: "m/44'/1'/1'",
|
||||
xpub: "tpubVossdTiJtheA1fQniKn9EN1JE1Eq1kBofaq2KwywrvuNhAk1KsEM7J2r8anhMJUmmcn9Wmoh73EctpW7Vxs3gS8cbF7N3m4zVjzuyvBj3qC",
|
||||
parser: testnetParser,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.parser.DerivationBasePath(tt.xpub)
|
||||
if err != nil {
|
||||
t.Errorf("DerivationBasePath() expected no error but got %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if got != tt.name {
|
||||
t.Errorf("DerivationBasePath() = %v, want %v", got, tt.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackAndUnpack(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
txInfo *bchain.Tx
|
||||
height uint32
|
||||
parser *DecredParser
|
||||
}{
|
||||
{
|
||||
name: "Test_1",
|
||||
txInfo: &testTx1,
|
||||
height: 15819,
|
||||
parser: testnetParser,
|
||||
},
|
||||
{
|
||||
name: "Test_2",
|
||||
txInfo: &testTx2,
|
||||
height: 300000,
|
||||
parser: mainnetParser,
|
||||
},
|
||||
{
|
||||
name: "Test_3",
|
||||
txInfo: &testTx3,
|
||||
height: 15859,
|
||||
parser: testnetParser,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
packedTx, err := tt.parser.PackTx(tt.txInfo, tt.height, tt.txInfo.Blocktime)
|
||||
if err != nil {
|
||||
t.Errorf("PackTx() expected no error but got %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
unpackedtx, gotHeight, err := tt.parser.UnpackTx(packedTx)
|
||||
if err != nil {
|
||||
t.Errorf("PackTx() expected no error but got %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.txInfo, unpackedtx) {
|
||||
t.Errorf("TestPackAndUnpack() expected the raw tx and the unpacked tx to match but they didn't")
|
||||
}
|
||||
|
||||
if gotHeight != tt.height {
|
||||
t.Errorf("TestPackAndUnpack() = got height %v, but want %v", gotHeight, tt.height)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue