github.com/bchainhub/blockbook@v0.3.2/bchain/coins/btc/bitcoinparser_test.go (about)

     1  // +build unittest
     2  
     3  package btc
     4  
     5  import (
     6  	"blockbook/bchain"
     7  	"encoding/hex"
     8  	"math/big"
     9  	"os"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/martinboehm/btcutil/chaincfg"
    14  )
    15  
    16  func TestMain(m *testing.M) {
    17  	c := m.Run()
    18  	chaincfg.ResetParams()
    19  	os.Exit(c)
    20  }
    21  
    22  func TestGetAddrDescFromAddress(t *testing.T) {
    23  	type args struct {
    24  		address string
    25  	}
    26  	tests := []struct {
    27  		name    string
    28  		args    args
    29  		want    string
    30  		wantErr bool
    31  	}{
    32  		{
    33  			name:    "P2PKH",
    34  			args:    args{address: "1JKgN43B9SyLuZH19H5ECvr4KcfrbVHzZ6"},
    35  			want:    "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac",
    36  			wantErr: false,
    37  		},
    38  		{
    39  			name:    "P2PKH from P2PK",
    40  			args:    args{address: "1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE"},
    41  			want:    "76a914b563933904dceba5c234e978bea0e9eb8b7e721b88ac",
    42  			wantErr: false,
    43  		},
    44  		{
    45  			name:    "P2SH",
    46  			args:    args{address: "321x69Cb9HZLWwAWGiUBT1U81r1zPLnEjL"},
    47  			want:    "a9140394b3cf9a44782c10105b93962daa8dba304d7f87",
    48  			wantErr: false,
    49  		},
    50  		{
    51  			name:    "P2WPKH",
    52  			args:    args{address: "bc1qrsf2l34jvqnq0lduyz0j5pfu2nkd93nnq0qggn"},
    53  			want:    "00141c12afc6b2602607fdbc209f2a053c54ecd2c673",
    54  			wantErr: false,
    55  		},
    56  		{
    57  			name:    "P2WSH",
    58  			args:    args{address: "bc1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355sw5exgr"},
    59  			want:    "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29",
    60  			wantErr: false,
    61  		},
    62  	}
    63  	parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})
    64  
    65  	for _, tt := range tests {
    66  		t.Run(tt.name, func(t *testing.T) {
    67  			got, err := parser.GetAddrDescFromAddress(tt.args.address)
    68  			if (err != nil) != tt.wantErr {
    69  				t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
    70  				return
    71  			}
    72  			h := hex.EncodeToString(got)
    73  			if !reflect.DeepEqual(h, tt.want) {
    74  				t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want)
    75  			}
    76  		})
    77  	}
    78  }
    79  
    80  func TestGetAddrDescFromVout(t *testing.T) {
    81  	type args struct {
    82  		vout bchain.Vout
    83  	}
    84  	tests := []struct {
    85  		name    string
    86  		args    args
    87  		want    string
    88  		wantErr bool
    89  	}{
    90  		{
    91  			name:    "P2PKH",
    92  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac"}}},
    93  			want:    "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac",
    94  			wantErr: false,
    95  		},
    96  		{
    97  			name:    "P2PK compressed 1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg",
    98  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"}}},
    99  			want:    "76a914f1dce4182fce875748c4986b240ff7d7bc3fffb088ac",
   100  			wantErr: false,
   101  		},
   102  		{
   103  			name:    "P2PK uncompressed 1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE",
   104  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"}}},
   105  			want:    "76a914b563933904dceba5c234e978bea0e9eb8b7e721b88ac",
   106  			wantErr: false,
   107  		},
   108  		{
   109  			name:    "P2SH",
   110  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"}}},
   111  			want:    "a9140394b3cf9a44782c10105b93962daa8dba304d7f87",
   112  			wantErr: false,
   113  		},
   114  		{
   115  			name:    "P2WPKH",
   116  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673"}}},
   117  			want:    "00141c12afc6b2602607fdbc209f2a053c54ecd2c673",
   118  			wantErr: false,
   119  		},
   120  		{
   121  			name:    "P2WSH",
   122  			args:    args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"}}},
   123  			want:    "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29",
   124  			wantErr: false,
   125  		},
   126  	}
   127  	parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})
   128  
   129  	for _, tt := range tests {
   130  		t.Run(tt.name, func(t *testing.T) {
   131  			got, err := parser.GetAddrDescFromVout(&tt.args.vout)
   132  			if (err != nil) != tt.wantErr {
   133  				t.Errorf("GetAddrDescFromVout() error = %v, wantErr %v", err, tt.wantErr)
   134  				return
   135  			}
   136  			h := hex.EncodeToString(got)
   137  			if !reflect.DeepEqual(h, tt.want) {
   138  				t.Errorf("GetAddrDescFromVout() = %v, want %v", h, tt.want)
   139  			}
   140  		})
   141  	}
   142  }
   143  
   144  func TestGetAddressesFromAddrDesc(t *testing.T) {
   145  	type args struct {
   146  		script string
   147  	}
   148  	tests := []struct {
   149  		name    string
   150  		args    args
   151  		want    []string
   152  		want2   bool
   153  		wantErr bool
   154  	}{
   155  		{
   156  			name:    "P2PKH",
   157  			args:    args{script: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac"},
   158  			want:    []string{"1JKgN43B9SyLuZH19H5ECvr4KcfrbVHzZ6"},
   159  			want2:   true,
   160  			wantErr: false,
   161  		},
   162  		{
   163  			name:    "P2PK compressed",
   164  			args:    args{script: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"},
   165  			want:    []string{"1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg"},
   166  			want2:   false,
   167  			wantErr: false,
   168  		},
   169  		{
   170  			name:    "P2PK uncompressed",
   171  			args:    args{script: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"},
   172  			want:    []string{"1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE"},
   173  			want2:   false,
   174  			wantErr: false,
   175  		},
   176  		{
   177  			name:    "P2SH",
   178  			args:    args{script: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"},
   179  			want:    []string{"321x69Cb9HZLWwAWGiUBT1U81r1zPLnEjL"},
   180  			want2:   true,
   181  			wantErr: false,
   182  		},
   183  		{
   184  			name:    "P2WPKH",
   185  			args:    args{script: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673"},
   186  			want:    []string{"bc1qrsf2l34jvqnq0lduyz0j5pfu2nkd93nnq0qggn"},
   187  			want2:   true,
   188  			wantErr: false,
   189  		},
   190  		{
   191  			name:    "P2WSH",
   192  			args:    args{script: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"},
   193  			want:    []string{"bc1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355sw5exgr"},
   194  			want2:   true,
   195  			wantErr: false,
   196  		},
   197  		{
   198  			name:    "OP_RETURN ascii",
   199  			args:    args{script: "6a0461686f6a"},
   200  			want:    []string{"OP_RETURN (ahoj)"},
   201  			want2:   false,
   202  			wantErr: false,
   203  		},
   204  		{
   205  			name:    "OP_RETURN OP_PUSHDATA1 ascii",
   206  			args:    args{script: "6a4c0b446c6f7568792074657874"},
   207  			want:    []string{"OP_RETURN (Dlouhy text)"},
   208  			want2:   false,
   209  			wantErr: false,
   210  		},
   211  		{
   212  			name:    "OP_RETURN hex",
   213  			args:    args{script: "6a072020f1686f6a20"},
   214  			want:    []string{"OP_RETURN 2020f1686f6a20"},
   215  			want2:   false,
   216  			wantErr: false,
   217  		},
   218  		{
   219  			name:    "OP_RETURN omni simple send tether",
   220  			args:    args{script: "6a146f6d6e69000000000000001f00000709bb647351"},
   221  			want:    []string{"OMNI Simple Send: 77383.80022609 TetherUS (#31)"},
   222  			want2:   false,
   223  			wantErr: false,
   224  		},
   225  		{
   226  			name:    "OP_RETURN omni simple send not supported coin",
   227  			args:    args{script: "6a146f6d6e69000000000000000300000709bb647351"},
   228  			want:    []string{"OP_RETURN 6f6d6e69000000000000000300000709bb647351"},
   229  			want2:   false,
   230  			wantErr: false,
   231  		},
   232  		{
   233  			name:    "OP_RETURN omni not supported version",
   234  			args:    args{script: "6a146f6d6e69010000000000000300000709bb647351"},
   235  			want:    []string{"OP_RETURN 6f6d6e69010000000000000300000709bb647351"},
   236  			want2:   false,
   237  			wantErr: false,
   238  		},
   239  	}
   240  
   241  	parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})
   242  
   243  	for _, tt := range tests {
   244  		t.Run(tt.name, func(t *testing.T) {
   245  			b, _ := hex.DecodeString(tt.args.script)
   246  			got, got2, err := parser.GetAddressesFromAddrDesc(b)
   247  			if (err != nil) != tt.wantErr {
   248  				t.Errorf("GetAddressesFromAddrDesc() error = %v, wantErr %v", err, tt.wantErr)
   249  				return
   250  			}
   251  			if !reflect.DeepEqual(got, tt.want) {
   252  				t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.want)
   253  			}
   254  			if !reflect.DeepEqual(got2, tt.want2) {
   255  				t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.want2)
   256  			}
   257  		})
   258  	}
   259  }
   260  
   261  var (
   262  	testTx1, testTx2 bchain.Tx
   263  
   264  	testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
   265  	testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
   266  )
   267  
   268  func init() {
   269  	testTx1 = bchain.Tx{
   270  		Hex:       "01000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700",
   271  		Blocktime: 1519053802,
   272  		Txid:      "056e3d82e5ffd0e915fb9b62797d76263508c34fe3e5dbed30dd3e943930f204",
   273  		LockTime:  512115,
   274  		Version:   1,
   275  		Vin: []bchain.Vin{
   276  			{
   277  				ScriptSig: bchain.ScriptSig{
   278  					Hex: "4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80",
   279  				},
   280  				Txid:     "425fed43ba74e9205875eb934d5bcf7bf338f146f70d4002d94bf5cbc9229a7f",
   281  				Vout:     4,
   282  				Sequence: 4294967294,
   283  			},
   284  		},
   285  		Vout: []bchain.Vout{
   286  			{
   287  				ValueSat: *big.NewInt(38812),
   288  				N:        0,
   289  				ScriptPubKey: bchain.ScriptPubKey{
   290  					Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87",
   291  					Addresses: []string{
   292  						"3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK",
   293  					},
   294  				},
   295  			},
   296  		},
   297  	}
   298  
   299  	testTx2 = bchain.Tx{
   300  		Hex:       "010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000",
   301  		Blocktime: 1235678901,
   302  		Txid:      "474e6795760ebe81cb4023dc227e5a0efe340e1771c89a0035276361ed733de7",
   303  		LockTime:  0,
   304  		Version:   1,
   305  		Vin: []bchain.Vin{
   306  			{
   307  				ScriptSig: bchain.ScriptSig{
   308  					Hex: "160014550da1f5d25a9dae2eafd6902b4194c4c6500af6",
   309  				},
   310  				Txid:     "c13e32a4428e31f85d7aee4ec7344504b12e72aaffcbde0160200d2ac7f0649d",
   311  				Vout:     0,
   312  				Sequence: 4294967295,
   313  			},
   314  		},
   315  		Vout: []bchain.Vout{
   316  			{
   317  				ValueSat: *big.NewInt(10000000),
   318  				N:        0,
   319  				ScriptPubKey: bchain.ScriptPubKey{
   320  					Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887",
   321  					Addresses: []string{
   322  						"2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu",
   323  					},
   324  				},
   325  			},
   326  			{
   327  				ValueSat: *big.NewInt(920081157),
   328  				N:        1,
   329  				ScriptPubKey: bchain.ScriptPubKey{
   330  					Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87",
   331  					Addresses: []string{
   332  						"2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D",
   333  					},
   334  				},
   335  			},
   336  		},
   337  	}
   338  }
   339  
   340  func TestPackTx(t *testing.T) {
   341  	type args struct {
   342  		tx        bchain.Tx
   343  		height    uint32
   344  		blockTime int64
   345  		parser    *BitcoinParser
   346  	}
   347  	tests := []struct {
   348  		name    string
   349  		args    args
   350  		want    string
   351  		wantErr bool
   352  	}{
   353  		{
   354  			name: "btc-1",
   355  			args: args{
   356  				tx:        testTx1,
   357  				height:    123456,
   358  				blockTime: 1519053802,
   359  				parser:    NewBitcoinParser(GetChainParams("main"), &Configuration{}),
   360  			},
   361  			want:    testTxPacked1,
   362  			wantErr: false,
   363  		},
   364  		{
   365  			name: "testnet-1",
   366  			args: args{
   367  				tx:        testTx2,
   368  				height:    510234,
   369  				blockTime: 1235678901,
   370  				parser:    NewBitcoinParser(GetChainParams("test"), &Configuration{}),
   371  			},
   372  			want:    testTxPacked2,
   373  			wantErr: false,
   374  		},
   375  	}
   376  	for _, tt := range tests {
   377  		t.Run(tt.name, func(t *testing.T) {
   378  			got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime)
   379  			if (err != nil) != tt.wantErr {
   380  				t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr)
   381  				return
   382  			}
   383  			h := hex.EncodeToString(got)
   384  			if !reflect.DeepEqual(h, tt.want) {
   385  				t.Errorf("packTx() = %v, want %v", h, tt.want)
   386  			}
   387  		})
   388  	}
   389  }
   390  
   391  func TestUnpackTx(t *testing.T) {
   392  	type args struct {
   393  		packedTx string
   394  		parser   *BitcoinParser
   395  	}
   396  	tests := []struct {
   397  		name    string
   398  		args    args
   399  		want    *bchain.Tx
   400  		want1   uint32
   401  		wantErr bool
   402  	}{
   403  		{
   404  			name: "btc-1",
   405  			args: args{
   406  				packedTx: testTxPacked1,
   407  				parser:   NewBitcoinParser(GetChainParams("main"), &Configuration{}),
   408  			},
   409  			want:    &testTx1,
   410  			want1:   123456,
   411  			wantErr: false,
   412  		},
   413  		{
   414  			name: "testnet-1",
   415  			args: args{
   416  				packedTx: testTxPacked2,
   417  				parser:   NewBitcoinParser(GetChainParams("test"), &Configuration{}),
   418  			},
   419  			want:    &testTx2,
   420  			want1:   510234,
   421  			wantErr: false,
   422  		},
   423  	}
   424  	for _, tt := range tests {
   425  		t.Run(tt.name, func(t *testing.T) {
   426  			b, _ := hex.DecodeString(tt.args.packedTx)
   427  			got, got1, err := tt.args.parser.UnpackTx(b)
   428  			if (err != nil) != tt.wantErr {
   429  				t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
   430  				return
   431  			}
   432  			if !reflect.DeepEqual(got, tt.want) {
   433  				t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
   434  			}
   435  			if got1 != tt.want1 {
   436  				t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1)
   437  			}
   438  		})
   439  	}
   440  }
   441  
   442  func TestDeriveAddressDescriptors(t *testing.T) {
   443  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   444  	type args struct {
   445  		xpub    string
   446  		change  uint32
   447  		indexes []uint32
   448  		parser  *BitcoinParser
   449  	}
   450  	tests := []struct {
   451  		name    string
   452  		args    args
   453  		want    []string
   454  		wantErr bool
   455  	}{
   456  		{
   457  			name: "m/44'/0'/0'",
   458  			args: args{
   459  				xpub:    "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   460  				change:  0,
   461  				indexes: []uint32{0, 1234},
   462  				parser:  btcMainParser,
   463  			},
   464  			want: []string{"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA", "1P9w11dXAmG3QBjKLAvCsek8izs1iR2iFi"},
   465  		},
   466  		{
   467  			name: "m/49'/0'/0'",
   468  			args: args{
   469  				xpub:    "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   470  				change:  0,
   471  				indexes: []uint32{0, 1234},
   472  				parser:  btcMainParser,
   473  			},
   474  			want: []string{"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf", "367meFzJ9KqDLm9PX6U8Z8RdmkSNBuxX8T"},
   475  		},
   476  		{
   477  			name: "m/84'/0'/0'",
   478  			args: args{
   479  				xpub:    "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   480  				change:  0,
   481  				indexes: []uint32{0, 1234},
   482  				parser:  btcMainParser,
   483  			},
   484  			want: []string{"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", "bc1q4nm6g46ujzyjaeusralaz2nfv2rf04jjfyamkw"},
   485  		},
   486  	}
   487  	for _, tt := range tests {
   488  		t.Run(tt.name, func(t *testing.T) {
   489  			got, err := tt.args.parser.DeriveAddressDescriptors(tt.args.xpub, tt.args.change, tt.args.indexes)
   490  			if (err != nil) != tt.wantErr {
   491  				t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr)
   492  				return
   493  			}
   494  			gotAddresses := make([]string, len(got))
   495  			for i, ad := range got {
   496  				aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad)
   497  				if err != nil || len(aa) != 1 {
   498  					t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err)
   499  					return
   500  				}
   501  				gotAddresses[i] = aa[0]
   502  			}
   503  			if !reflect.DeepEqual(gotAddresses, tt.want) {
   504  				t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want)
   505  			}
   506  		})
   507  	}
   508  }
   509  
   510  func TestDeriveAddressDescriptorsFromTo(t *testing.T) {
   511  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   512  	btcTestnetsParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198})
   513  	type args struct {
   514  		xpub      string
   515  		change    uint32
   516  		fromIndex uint32
   517  		toIndex   uint32
   518  		parser    *BitcoinParser
   519  	}
   520  	tests := []struct {
   521  		name    string
   522  		args    args
   523  		want    []string
   524  		wantErr bool
   525  	}{
   526  		{
   527  			name: "m/44'/0'/0'",
   528  			args: args{
   529  				xpub:      "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj",
   530  				change:    0,
   531  				fromIndex: 0,
   532  				toIndex:   1,
   533  				parser:    btcMainParser,
   534  			},
   535  			want: []string{"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA"},
   536  		},
   537  		{
   538  			name: "m/49'/0'/0'",
   539  			args: args{
   540  				xpub:      "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP",
   541  				change:    0,
   542  				fromIndex: 0,
   543  				toIndex:   1,
   544  				parser:    btcMainParser,
   545  			},
   546  			want: []string{"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"},
   547  		},
   548  		{
   549  			name: "m/84'/0'/0'",
   550  			args: args{
   551  				xpub:      "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   552  				change:    0,
   553  				fromIndex: 0,
   554  				toIndex:   1,
   555  				parser:    btcMainParser,
   556  			},
   557  			want: []string{"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"},
   558  		},
   559  		{
   560  			name: "m/49'/1'/0'",
   561  			args: args{
   562  				xpub:      "upub5DR1Mg5nykixzYjFXWW5GghAU7dDqoPVJ2jrqFbL8sJ7Hs7jn69MP7KBnnmxn88GeZtnH8PRKV9w5MMSFX8AdEAoXY8Qd8BJPoXtpMeHMxJ",
   563  				change:    0,
   564  				fromIndex: 0,
   565  				toIndex:   10,
   566  				parser:    btcTestnetsParser,
   567  			},
   568  			want: []string{"2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp", "2Mt7P2BAfE922zmfXrdcYTLyR7GUvbwSEns", "2N6aUMgQk8y1zvoq6FeWFyotyj75WY9BGsu", "2NA7tbZWM9BcRwBuebKSQe2xbhhF1paJwBM", "2N8RZMzvrUUnpLmvACX9ysmJ2MX3GK5jcQM", "2MvUUSiQZDSqyeSdofKX9KrSCio1nANPDTe", "2NBXaWu1HazjoUVgrXgcKNoBLhtkkD9Gmet", "2N791Ttf89tMVw2maj86E1Y3VgxD9Mc7PU7", "2NCJmwEq8GJm8t8GWWyBXAfpw7F2qZEVP5Y", "2NEgW71hWKer2XCSA8ZCC2VnWpB77L6bk68"},
   569  		},
   570  	}
   571  	for _, tt := range tests {
   572  		t.Run(tt.name, func(t *testing.T) {
   573  			got, err := tt.args.parser.DeriveAddressDescriptorsFromTo(tt.args.xpub, tt.args.change, tt.args.fromIndex, tt.args.toIndex)
   574  			if (err != nil) != tt.wantErr {
   575  				t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr)
   576  				return
   577  			}
   578  			gotAddresses := make([]string, len(got))
   579  			for i, ad := range got {
   580  				aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad)
   581  				if err != nil || len(aa) != 1 {
   582  					t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err)
   583  					return
   584  				}
   585  				gotAddresses[i] = aa[0]
   586  			}
   587  			if !reflect.DeepEqual(gotAddresses, tt.want) {
   588  				t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want)
   589  			}
   590  		})
   591  	}
   592  }
   593  
   594  func BenchmarkDeriveAddressDescriptorsFromToXpub(b *testing.B) {
   595  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   596  	for i := 0; i < b.N; i++ {
   597  		btcMainParser.DeriveAddressDescriptorsFromTo("xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", 1, 0, 100)
   598  	}
   599  }
   600  
   601  func BenchmarkDeriveAddressDescriptorsFromToYpub(b *testing.B) {
   602  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   603  	for i := 0; i < b.N; i++ {
   604  		btcMainParser.DeriveAddressDescriptorsFromTo("ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", 1, 0, 100)
   605  	}
   606  }
   607  
   608  func BenchmarkDeriveAddressDescriptorsFromToZpub(b *testing.B) {
   609  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518})
   610  	for i := 0; i < b.N; i++ {
   611  		btcMainParser.DeriveAddressDescriptorsFromTo("zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", 1, 0, 100)
   612  	}
   613  }
   614  
   615  func TestBitcoinParser_DerivationBasePath(t *testing.T) {
   616  	btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518, Slip44: 0})
   617  	btcTestnetsParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198, Slip44: 1})
   618  	zecMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, Slip44: 133})
   619  	type args struct {
   620  		xpub   string
   621  		parser *BitcoinParser
   622  	}
   623  	tests := []struct {
   624  		name    string
   625  		args    args
   626  		want    string
   627  		wantErr bool
   628  	}{
   629  		{
   630  			name: "m/84'/0'/0'",
   631  			args: args{
   632  				xpub:   "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs",
   633  				parser: btcMainParser,
   634  			},
   635  			want: "m/84'/0'/0'",
   636  		},
   637  		{
   638  			name: "m/49'/0'/55 - not hardened account",
   639  			args: args{
   640  				xpub:   "ypub6XKbB5DJRAbW4TRJLp4uXQXG3ob5BtByXsNZFBjq9qcbzrczjVXfCz5cEo1SFDexmeWRnbCMDaRgaW4m9d2nBaa8FvUQCu3n9G1UBR8WhbT",
   641  				parser: btcMainParser,
   642  			},
   643  			want: "m/49'/0'/55",
   644  		},
   645  		{
   646  			name: "m/49'/0' - incomplete path, without account",
   647  			args: args{
   648  				xpub:   "ypub6UzM8PUqxcSoqC9gumfoiFhE8Qt84HbGpCD4eVJfJAojXTVtBxeddvTWJGJhGoaVBNJLmEgMdLXHgaLVJa4xEvk2tcokkdZhFdkxMLUE9sB",
   649  				parser: btcMainParser,
   650  			},
   651  			want: "unknown/0'",
   652  		},
   653  		{
   654  			name: "m/49'/1'/0'",
   655  			args: args{
   656  				xpub:   "upub5DR1Mg5nykixzYjFXWW5GghAU7dDqoPVJ2jrqFbL8sJ7Hs7jn69MP7KBnnmxn88GeZtnH8PRKV9w5MMSFX8AdEAoXY8Qd8BJPoXtpMeHMxJ",
   657  				parser: btcTestnetsParser,
   658  			},
   659  			want: "m/49'/1'/0'",
   660  		},
   661  		{
   662  			name: "m/44'/133'/12'",
   663  			args: args{
   664  				xpub:   "xpub6CQdEahwhKRTLYpP6cyb7ZaGb3r4tVdyPX6dC1PfrNuByrCkWDgUkmpD28UdV9QccKgY1ZiAbGv1Fakcg2LxdFVSTNKHcjdRjqhjPK8Trkb",
   665  				parser: zecMainParser,
   666  			},
   667  			want: "m/44'/133'/12'",
   668  		},
   669  	}
   670  	for _, tt := range tests {
   671  		t.Run(tt.name, func(t *testing.T) {
   672  			got, err := tt.args.parser.DerivationBasePath(tt.args.xpub)
   673  			if (err != nil) != tt.wantErr {
   674  				t.Errorf("BitcoinParser.DerivationBasePath() error = %v, wantErr %v", err, tt.wantErr)
   675  				return
   676  			}
   677  			if got != tt.want {
   678  				t.Errorf("BitcoinParser.DerivationBasePath() = %v, want %v", got, tt.want)
   679  			}
   680  		})
   681  	}
   682  }