github.com/cryptohub-digital/blockbook-fork@v0.0.0-20230713133354-673c927af7f1/bchain/coins/btc/bitcoinparser_test.go (about) 1 //go:build unittest 2 3 package btc 4 5 import ( 6 "encoding/hex" 7 "math/big" 8 "os" 9 "reflect" 10 "testing" 11 12 "github.com/cryptohub-digital/blockbook-fork/bchain" 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 name: " witness_unknown v1", 64 args: args{address: "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y"}, 65 want: "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6", 66 wantErr: false, 67 }, 68 { 69 name: " witness_unknown v16", 70 args: args{address: "bc1sw50qgdz25j"}, 71 want: "6002751e", 72 wantErr: false, 73 }, 74 } 75 parser := NewBitcoinParser(GetChainParams("main"), &Configuration{}) 76 77 for _, tt := range tests { 78 t.Run(tt.name, func(t *testing.T) { 79 got, err := parser.GetAddrDescFromAddress(tt.args.address) 80 if (err != nil) != tt.wantErr { 81 t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr) 82 return 83 } 84 h := hex.EncodeToString(got) 85 if !reflect.DeepEqual(h, tt.want) { 86 t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want) 87 } 88 }) 89 } 90 } 91 92 func TestGetAddrDescFromAddressTestnet(t *testing.T) { 93 type args struct { 94 address string 95 } 96 tests := []struct { 97 name string 98 args args 99 want string 100 wantErr bool 101 }{ 102 { 103 name: "pubkeyhash", 104 args: args{address: "mtkbaiLiUH3fvGJeSzuN3kUgmJzqinLejJ"}, 105 want: "76a914912e2b234f941f30b18afbb4fa46171214bf66c888ac", 106 wantErr: false, 107 }, 108 { 109 name: "scripthash", 110 args: args{address: "2Mv28xcUJdFXBTfGMtja6fVBMCEbsH3r2AW"}, 111 want: "a9141e6ec5a1d12912b396d77d98dcb000e91f517fa487", 112 wantErr: false, 113 }, 114 { 115 name: "witness_v0_keyhash", 116 args: args{address: "tb1qupjdck20as3y4l95cd5wepkv0grcz0p7d8rd5s"}, 117 want: "0014e064dc594fec224afcb4c368ec86cc7a07813c3e", 118 wantErr: false, 119 }, 120 { 121 name: "witness_v0_scripthash", 122 args: args{address: "tb1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355seu0fjv"}, 123 want: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29", 124 wantErr: false, 125 }, 126 { 127 name: "witness_v1_taproot", 128 args: args{address: "tb1pqsv2qyp8hsma46422ecfd3ek02jayumkkzjx7vkf3cqpmfd4ucpsx0cc9h"}, 129 want: "51200418a01027bc37daeaaa567096c7367aa5d27376b0a46f32c98e001da5b5e603", 130 wantErr: false, 131 }, 132 } 133 parser := NewBitcoinParser(GetChainParams("test"), &Configuration{}) 134 135 for _, tt := range tests { 136 t.Run(tt.name, func(t *testing.T) { 137 got, err := parser.GetAddrDescFromAddress(tt.args.address) 138 if (err != nil) != tt.wantErr { 139 t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr) 140 return 141 } 142 h := hex.EncodeToString(got) 143 if !reflect.DeepEqual(h, tt.want) { 144 t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want) 145 } 146 }) 147 } 148 } 149 150 func TestGetAddrDescFromVout(t *testing.T) { 151 type args struct { 152 vout bchain.Vout 153 } 154 tests := []struct { 155 name string 156 args args 157 want string 158 wantErr bool 159 }{ 160 { 161 name: "P2PKH", 162 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac"}}}, 163 want: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac", 164 wantErr: false, 165 }, 166 { 167 name: "P2PK compressed 1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg", 168 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"}}}, 169 want: "76a914f1dce4182fce875748c4986b240ff7d7bc3fffb088ac", 170 wantErr: false, 171 }, 172 { 173 name: "P2PK uncompressed 1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE", 174 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"}}}, 175 want: "76a914b563933904dceba5c234e978bea0e9eb8b7e721b88ac", 176 wantErr: false, 177 }, 178 { 179 name: "P2SH", 180 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"}}}, 181 want: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87", 182 wantErr: false, 183 }, 184 { 185 name: "P2WPKH", 186 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673"}}}, 187 want: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673", 188 wantErr: false, 189 }, 190 { 191 name: "P2WSH", 192 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"}}}, 193 want: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29", 194 wantErr: false, 195 }, 196 } 197 parser := NewBitcoinParser(GetChainParams("main"), &Configuration{}) 198 199 for _, tt := range tests { 200 t.Run(tt.name, func(t *testing.T) { 201 got, err := parser.GetAddrDescFromVout(&tt.args.vout) 202 if (err != nil) != tt.wantErr { 203 t.Errorf("GetAddrDescFromVout() error = %v, wantErr %v", err, tt.wantErr) 204 return 205 } 206 h := hex.EncodeToString(got) 207 if !reflect.DeepEqual(h, tt.want) { 208 t.Errorf("GetAddrDescFromVout() = %v, want %v", h, tt.want) 209 } 210 }) 211 } 212 } 213 214 func TestGetAddressesFromAddrDesc(t *testing.T) { 215 type args struct { 216 script string 217 } 218 tests := []struct { 219 name string 220 args args 221 want []string 222 want2 bool 223 wantErr bool 224 }{ 225 { 226 name: "P2PKH", 227 args: args{script: "76a914be027bf3eac907bd4ac8cb9c5293b6f37662722088ac"}, 228 want: []string{"1JKgN43B9SyLuZH19H5ECvr4KcfrbVHzZ6"}, 229 want2: true, 230 wantErr: false, 231 }, 232 { 233 name: "P2PK compressed", 234 args: args{script: "21020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9ac"}, 235 want: []string{"1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg"}, 236 want2: false, 237 wantErr: false, 238 }, 239 { 240 name: "P2PK uncompressed", 241 args: args{script: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"}, 242 want: []string{"1HY6bKYhFH7HF3F48ikvziPHLrEWPGwXcE"}, 243 want2: false, 244 wantErr: false, 245 }, 246 { 247 name: "P2SH", 248 args: args{script: "a9140394b3cf9a44782c10105b93962daa8dba304d7f87"}, 249 want: []string{"321x69Cb9HZLWwAWGiUBT1U81r1zPLnEjL"}, 250 want2: true, 251 wantErr: false, 252 }, 253 { 254 name: "P2WPKH", 255 args: args{script: "00141c12afc6b2602607fdbc209f2a053c54ecd2c673"}, 256 want: []string{"bc1qrsf2l34jvqnq0lduyz0j5pfu2nkd93nnq0qggn"}, 257 want2: true, 258 wantErr: false, 259 }, 260 { 261 name: "P2WSH", 262 args: args{script: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"}, 263 want: []string{"bc1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355sw5exgr"}, 264 want2: true, 265 wantErr: false, 266 }, 267 { 268 name: "OP_RETURN ascii", 269 args: args{script: "6a0461686f6a"}, 270 want: []string{"OP_RETURN (ahoj)"}, 271 want2: false, 272 wantErr: false, 273 }, 274 { 275 name: "OP_RETURN OP_PUSHDATA1 ascii", 276 args: args{script: "6a4c0b446c6f7568792074657874"}, 277 want: []string{"OP_RETURN (Dlouhy text)"}, 278 want2: false, 279 wantErr: false, 280 }, 281 { 282 name: "OP_RETURN OP_PUSHDATA1 utf8", 283 args: args{script: "6a31e5bfabe981a9e381ab4254434658e58f96e5bc95e3818ce381a7e3818de3828b5043e3818ce6acb2e38197e38184e38082"}, 284 want: []string{"OP_RETURN (快適にBTCFX取引ができるPCが欲しい。)"}, 285 want2: false, 286 wantErr: false, 287 }, 288 { 289 name: "OP_RETURN OP_PUSHDATA2 ascii", 290 args: args{script: "6a4dd7035765277265206e6f20737472616e6765727320746f206c6f76650a596f75206b6e6f77207468652072756c657320616e6420736f20646f20490a412066756c6c20636f6d6d69746d656e74277320776861742049276d207468696e6b696e67206f660a596f7520776f756c646e27742067657420746869732066726f6d20616e79206f74686572206775790a49206a7573742077616e6e612074656c6c20796f7520686f772049276d206665656c696e670a476f747461206d616b6520796f7520756e6465727374616e640a0a43484f5255530a4e6576657220676f6e6e61206769766520796f752075702c0a4e6576657220676f6e6e61206c657420796f7520646f776e0a4e6576657220676f6e6e612072756e2061726f756e6420616e642064657365727420796f750a4e6576657220676f6e6e61206d616b6520796f75206372792c0a4e6576657220676f6e6e612073617920676f6f646279650a4e6576657220676f6e6e612074656c6c2061206c696520616e64206875727420796f750a0a5765277665206b6e6f776e2065616368206f7468657220666f7220736f206c6f6e670a596f75722068656172742773206265656e20616368696e672062757420796f7527726520746f6f2073687920746f207361792069740a496e7369646520776520626f7468206b6e6f7720776861742773206265656e20676f696e67206f6e0a5765206b6e6f77207468652067616d6520616e6420776527726520676f6e6e6120706c61792069740a416e6420696620796f752061736b206d6520686f772049276d206665656c696e670a446f6e27742074656c6c206d6520796f7527726520746f6f20626c696e6420746f20736565202843484f525553290a0a43484f52555343484f5255530a284f6f68206769766520796f75207570290a284f6f68206769766520796f75207570290a284f6f6829206e6576657220676f6e6e6120676976652c206e6576657220676f6e6e6120676976650a286769766520796f75207570290a284f6f6829206e6576657220676f6e6e6120676976652c206e6576657220676f6e6e6120676976650a286769766520796f75207570290a0a5765277665206b6e6f776e2065616368206f7468657220666f7220736f206c6f6e670a596f75722068656172742773206265656e20616368696e672062757420796f7527726520746f6f2073687920746f207361792069740a496e7369646520776520626f7468206b6e6f7720776861742773206265656e20676f696e67206f6e0a5765206b6e6f77207468652067616d6520616e6420776527726520676f6e6e6120706c61792069742028544f2046524f4e54290a0a"}, 291 want: []string{`OP_RETURN (We're no strangers to love 292 You know the rules and so do I 293 A full commitment's what I'm thinking of 294 You wouldn't get this from any other guy 295 I just wanna tell you how I'm feeling 296 Gotta make you understand 297 298 CHORUS 299 Never gonna give you up, 300 Never gonna let you down 301 Never gonna run around and desert you 302 Never gonna make you cry, 303 Never gonna say goodbye 304 Never gonna tell a lie and hurt you 305 306 We've known each other for so long 307 Your heart's been aching but you're too shy to say it 308 Inside we both know what's been going on 309 We know the game and we're gonna play it 310 And if you ask me how I'm feeling 311 Don't tell me you're too blind to see (CHORUS) 312 313 CHORUSCHORUS 314 (Ooh give you up) 315 (Ooh give you up) 316 (Ooh) never gonna give, never gonna give 317 (give you up) 318 (Ooh) never gonna give, never gonna give 319 (give you up) 320 321 We've known each other for so long 322 Your heart's been aching but you're too shy to say it 323 Inside we both know what's been going on 324 We know the game and we're gonna play it (TO FRONT) 325 326 )`}, 327 want2: false, 328 wantErr: false, 329 }, 330 { 331 name: "OP_RETURN hex", 332 args: args{script: "6a072020f1686f6a20"}, 333 want: []string{"OP_RETURN 2020f1686f6a20"}, 334 want2: false, 335 wantErr: false, 336 }, 337 { 338 name: "OP_RETURN omni simple send tether", 339 args: args{script: "6a146f6d6e69000000000000001f00000709bb647351"}, 340 want: []string{"OMNI Simple Send: 77383.80022609 TetherUS (#31)"}, 341 want2: false, 342 wantErr: false, 343 }, 344 { 345 name: "OP_RETURN omni simple send not supported coin", 346 args: args{script: "6a146f6d6e69000000000000000300000709bb647351"}, 347 want: []string{"OP_RETURN 6f6d6e69000000000000000300000709bb647351"}, 348 want2: false, 349 wantErr: false, 350 }, 351 { 352 name: "OP_RETURN omni not supported version", 353 args: args{script: "6a146f6d6e69010000000000000300000709bb647351"}, 354 want: []string{"OP_RETURN 6f6d6e69010000000000000300000709bb647351"}, 355 want2: false, 356 wantErr: false, 357 }, 358 } 359 360 parser := NewBitcoinParser(GetChainParams("main"), &Configuration{}) 361 362 for _, tt := range tests { 363 t.Run(tt.name, func(t *testing.T) { 364 b, _ := hex.DecodeString(tt.args.script) 365 got, got2, err := parser.GetAddressesFromAddrDesc(b) 366 if (err != nil) != tt.wantErr { 367 t.Errorf("GetAddressesFromAddrDesc() error = %v, wantErr %v", err, tt.wantErr) 368 return 369 } 370 if !reflect.DeepEqual(got, tt.want) { 371 t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.want) 372 } 373 if !reflect.DeepEqual(got2, tt.want2) { 374 t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.want2) 375 } 376 }) 377 } 378 } 379 380 func TestGetAddressesFromAddrDescTestnet(t *testing.T) { 381 type args struct { 382 script string 383 } 384 tests := []struct { 385 name string 386 args args 387 want []string 388 want2 bool 389 wantErr bool 390 }{ 391 { 392 name: "pubkeyhash", 393 args: args{script: "76a914912e2b234f941f30b18afbb4fa46171214bf66c888ac"}, 394 want: []string{"mtkbaiLiUH3fvGJeSzuN3kUgmJzqinLejJ"}, 395 want2: true, 396 wantErr: false, 397 }, 398 { 399 name: "pubkey compressed", 400 args: args{script: "2102a741071164b40b01c4ad28913c4aa2a1015cc5b064f0c802272552f17ae08750ac"}, 401 want: []string{"mkMe1fsfCWFext2qxf4bk3yiruBTvnici4"}, 402 want2: false, 403 wantErr: false, 404 }, 405 { 406 name: "pubkey uncompressed", 407 args: args{script: "41041057356b91bfd3efeff5fc0fa8b865faafafb67bd653c5da2cd16ce15c7b86db0e622c8e1e135f68918a23601eb49208c1ac72c7b64a4ee99c396cf788da16ccac"}, 408 want: []string{"mx43tNdg4JYY29ifrHjJpdbcCqqDGVSng5"}, 409 want2: false, 410 wantErr: false, 411 }, 412 { 413 name: "scripthash", 414 args: args{script: "a9141e6ec5a1d12912b396d77d98dcb000e91f517fa487"}, 415 want: []string{"2Mv28xcUJdFXBTfGMtja6fVBMCEbsH3r2AW"}, 416 want2: true, 417 wantErr: false, 418 }, 419 { 420 name: "witness_v0_keyhash", 421 args: args{script: "0014e064dc594fec224afcb4c368ec86cc7a07813c3e"}, 422 want: []string{"tb1qupjdck20as3y4l95cd5wepkv0grcz0p7d8rd5s"}, 423 want2: true, 424 wantErr: false, 425 }, 426 { 427 name: "witness_v0_scripthash", 428 args: args{script: "002003973a40ec94c0d10f6f6f0e7a62ba2044b7d19db6ff2bf60651e17fb29d8d29"}, 429 want: []string{"tb1qqwtn5s8vjnqdzrm0du885c46ypzt05vakmljhasx28shlv5a355seu0fjv"}, 430 want2: true, 431 wantErr: false, 432 }, 433 { 434 name: "witness_v1_taproot", 435 args: args{script: "51200418a01027bc37daeaaa567096c7367aa5d27376b0a46f32c98e001da5b5e603"}, 436 want: []string{"tb1pqsv2qyp8hsma46422ecfd3ek02jayumkkzjx7vkf3cqpmfd4ucpsx0cc9h"}, 437 want2: true, 438 wantErr: false, 439 }, 440 { 441 name: "OP_RETURN ascii", 442 args: args{script: "6a0461686f6a"}, 443 want: []string{"OP_RETURN (ahoj)"}, 444 want2: false, 445 wantErr: false, 446 }, 447 } 448 449 parser := NewBitcoinParser(GetChainParams("test"), &Configuration{}) 450 451 for _, tt := range tests { 452 t.Run(tt.name, func(t *testing.T) { 453 b, _ := hex.DecodeString(tt.args.script) 454 got, got2, err := parser.GetAddressesFromAddrDesc(b) 455 if (err != nil) != tt.wantErr { 456 t.Errorf("TestGetAddressesFromAddrDesc_Testnet() error = %v, wantErr %v", err, tt.wantErr) 457 return 458 } 459 if !reflect.DeepEqual(got, tt.want) { 460 t.Errorf("TestGetAddressesFromAddrDesc_Testnet() = %v, want %v", got, tt.want) 461 } 462 if !reflect.DeepEqual(got2, tt.want2) { 463 t.Errorf("TestGetAddressesFromAddrDesc_Testnet() = %v, want %v", got2, tt.want2) 464 } 465 }) 466 } 467 } 468 469 var ( 470 testTx1, testTx2, testTx3 bchain.Tx 471 472 testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700" 473 testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000" 474 testTxPacked3 = "00003d818bfda9aa3e02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000" 475 ) 476 477 func init() { 478 testTx1 = bchain.Tx{ 479 Hex: "01000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700", 480 Blocktime: 1519053802, 481 Txid: "056e3d82e5ffd0e915fb9b62797d76263508c34fe3e5dbed30dd3e943930f204", 482 LockTime: 512115, 483 VSize: 189, 484 Version: 1, 485 Vin: []bchain.Vin{ 486 { 487 ScriptSig: bchain.ScriptSig{ 488 Hex: "4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80", 489 }, 490 Txid: "425fed43ba74e9205875eb934d5bcf7bf338f146f70d4002d94bf5cbc9229a7f", 491 Vout: 4, 492 Sequence: 4294967294, 493 }, 494 }, 495 Vout: []bchain.Vout{ 496 { 497 ValueSat: *big.NewInt(38812), 498 N: 0, 499 ScriptPubKey: bchain.ScriptPubKey{ 500 Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87", 501 Addresses: []string{ 502 "3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", 503 }, 504 }, 505 }, 506 }, 507 } 508 509 testTx2 = bchain.Tx{ 510 Hex: "010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000", 511 Blocktime: 1235678901, 512 Txid: "474e6795760ebe81cb4023dc227e5a0efe340e1771c89a0035276361ed733de7", 513 LockTime: 0, 514 VSize: 166, 515 Version: 1, 516 Vin: []bchain.Vin{ 517 { 518 ScriptSig: bchain.ScriptSig{ 519 Hex: "160014550da1f5d25a9dae2eafd6902b4194c4c6500af6", 520 }, 521 Txid: "c13e32a4428e31f85d7aee4ec7344504b12e72aaffcbde0160200d2ac7f0649d", 522 Vout: 0, 523 Sequence: 4294967295, 524 }, 525 }, 526 Vout: []bchain.Vout{ 527 { 528 ValueSat: *big.NewInt(10000000), 529 N: 0, 530 ScriptPubKey: bchain.ScriptPubKey{ 531 Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887", 532 Addresses: []string{ 533 "2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", 534 }, 535 }, 536 }, 537 { 538 ValueSat: *big.NewInt(920081157), 539 N: 1, 540 ScriptPubKey: bchain.ScriptPubKey{ 541 Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87", 542 Addresses: []string{ 543 "2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", 544 }, 545 }, 546 }, 547 }, 548 } 549 550 testTx3 = bchain.Tx{ 551 Hex: "02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000", 552 Blocktime: 1607805599, 553 Txid: "24551a58a1d1fb89d7052e2bbac7cb69a7825ee1e39439befbec8c32148cf735", 554 LockTime: 15745, 555 VSize: 208, 556 Version: 2, 557 Vin: []bchain.Vin{ 558 { 559 ScriptSig: bchain.ScriptSig{ 560 Hex: "", 561 }, 562 Txid: "9d8b6a98d942ce077574fff2e5dd9e405ba75ed9fb126b3da1b07a859a99b1de", 563 Vout: 0, 564 Sequence: 4294967293, 565 }, 566 { 567 ScriptSig: bchain.ScriptSig{ 568 Hex: "", 569 }, 570 Txid: "98227ffe94726bc77c3c587e1e5375305beffb8e43a6eb75233b201e36d3d29f", 571 Vout: 0, 572 Sequence: 4294967293, 573 }, 574 }, 575 Vout: []bchain.Vout{ 576 { 577 ValueSat: *big.NewInt(100000), 578 N: 0, 579 ScriptPubKey: bchain.ScriptPubKey{ 580 Hex: "00148091746745464e7555c31e9a5afceac14a02978a", 581 Addresses: []string{ 582 "tb1qszghge69ge8824wrr6d94l82c99q99u2ccgv5w", 583 }, 584 }, 585 }, 586 { 587 ValueSat: *big.NewInt(1899751), 588 N: 1, 589 ScriptPubKey: bchain.ScriptPubKey{ 590 Hex: "0014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e", 591 Addresses: []string{ 592 "tb1q2e02nl6938f7qkapfxhxufth22lac2s792vsxp", 593 }, 594 }, 595 }, 596 }, 597 } 598 } 599 600 func TestPackTx(t *testing.T) { 601 type args struct { 602 tx bchain.Tx 603 height uint32 604 blockTime int64 605 parser *BitcoinParser 606 } 607 tests := []struct { 608 name string 609 args args 610 want string 611 wantErr bool 612 }{ 613 { 614 name: "btc-1", 615 args: args{ 616 tx: testTx1, 617 height: 123456, 618 blockTime: 1519053802, 619 parser: NewBitcoinParser(GetChainParams("main"), &Configuration{}), 620 }, 621 want: testTxPacked1, 622 wantErr: false, 623 }, 624 { 625 name: "testnet-1", 626 args: args{ 627 tx: testTx2, 628 height: 510234, 629 blockTime: 1235678901, 630 parser: NewBitcoinParser(GetChainParams("test"), &Configuration{}), 631 }, 632 want: testTxPacked2, 633 wantErr: false, 634 }, 635 { 636 name: "signet-1", 637 args: args{ 638 tx: testTx3, 639 height: 15745, 640 blockTime: 1607805599, 641 parser: NewBitcoinParser(GetChainParams("signet"), &Configuration{}), 642 }, 643 want: testTxPacked3, 644 wantErr: false, 645 }, 646 } 647 for _, tt := range tests { 648 t.Run(tt.name, func(t *testing.T) { 649 got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime) 650 if (err != nil) != tt.wantErr { 651 t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr) 652 return 653 } 654 h := hex.EncodeToString(got) 655 if !reflect.DeepEqual(h, tt.want) { 656 t.Errorf("packTx() = %v, want %v", h, tt.want) 657 } 658 }) 659 } 660 } 661 662 func TestUnpackTx(t *testing.T) { 663 type args struct { 664 packedTx string 665 parser *BitcoinParser 666 } 667 tests := []struct { 668 name string 669 args args 670 want *bchain.Tx 671 want1 uint32 672 wantErr bool 673 }{ 674 { 675 name: "btc-1", 676 args: args{ 677 packedTx: testTxPacked1, 678 parser: NewBitcoinParser(GetChainParams("main"), &Configuration{}), 679 }, 680 want: &testTx1, 681 want1: 123456, 682 wantErr: false, 683 }, 684 { 685 name: "testnet-1", 686 args: args{ 687 packedTx: testTxPacked2, 688 parser: NewBitcoinParser(GetChainParams("test"), &Configuration{}), 689 }, 690 want: &testTx2, 691 want1: 510234, 692 wantErr: false, 693 }, 694 { 695 name: "signet-1", 696 args: args{ 697 packedTx: testTxPacked3, 698 parser: NewBitcoinParser(GetChainParams("signet"), &Configuration{}), 699 }, 700 want: &testTx3, 701 want1: 15745, 702 wantErr: false, 703 }, 704 } 705 for _, tt := range tests { 706 t.Run(tt.name, func(t *testing.T) { 707 b, _ := hex.DecodeString(tt.args.packedTx) 708 got, got1, err := tt.args.parser.UnpackTx(b) 709 if (err != nil) != tt.wantErr { 710 t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr) 711 return 712 } 713 if !reflect.DeepEqual(got, tt.want) { 714 t.Errorf("unpackTx() got = %v, want %v", got, tt.want) 715 } 716 if got1 != tt.want1 { 717 t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1) 718 } 719 }) 720 } 721 } 722 723 func TestParseXpubDescriptors(t *testing.T) { 724 btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518}) 725 btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198}) 726 tests := []struct { 727 name string 728 xpub string 729 parser *BitcoinParser 730 want *bchain.XpubDescriptor 731 wantErr bool 732 }{ 733 { 734 name: "tpub", 735 xpub: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN", 736 parser: btcTestnetParser, 737 want: &bchain.XpubDescriptor{ 738 XpubDescriptor: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN", 739 Xpub: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN", 740 Type: bchain.P2PKH, 741 Bip: "44", 742 ChangeIndexes: []uint32{0, 1}, 743 }, 744 }, 745 { 746 name: "tr(tpub)", 747 xpub: "tr(tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN)", 748 parser: btcTestnetParser, 749 want: &bchain.XpubDescriptor{ 750 XpubDescriptor: "tr(tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN)", 751 Xpub: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN", 752 Type: bchain.P2TR, 753 Bip: "86", 754 ChangeIndexes: []uint32{0, 1}, 755 }, 756 }, 757 { 758 name: "tr([5c9e228d/86'/1'/0']tpubD/{0,1,2}/*)#4rqwxvej", 759 xpub: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/{0,1,2}/*)#4rqwxvej", 760 parser: btcTestnetParser, 761 want: &bchain.XpubDescriptor{ 762 XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/{0,1,2}/*)#4rqwxvej", 763 Xpub: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN", 764 Type: bchain.P2TR, 765 Bip: "86", 766 ChangeIndexes: []uint32{0, 1, 2}, 767 }, 768 }, 769 { 770 name: "tr([5c9e228d/86'/1'/0']tpubD/<0;1;2>/*)#4rqwxvej", 771 xpub: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/<0;1;2>/*)#4rqwxvej", 772 parser: btcTestnetParser, 773 want: &bchain.XpubDescriptor{ 774 XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/<0;1;2>/*)#4rqwxvej", 775 Xpub: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN", 776 Type: bchain.P2TR, 777 Bip: "86", 778 ChangeIndexes: []uint32{0, 1, 2}, 779 }, 780 }, 781 { 782 name: "tr([5c9e228d/86'/1'/0']tpubD/3/*)#4rqwxvej", 783 xpub: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/3/*)#4rqwxvej", 784 parser: btcTestnetParser, 785 want: &bchain.XpubDescriptor{ 786 XpubDescriptor: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/3/*)#4rqwxvej", 787 Xpub: "tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN", 788 Type: bchain.P2TR, 789 Bip: "86", 790 ChangeIndexes: []uint32{3}, 791 }, 792 }, 793 { 794 name: "xpub", 795 xpub: "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", 796 parser: btcMainParser, 797 want: &bchain.XpubDescriptor{ 798 XpubDescriptor: "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", 799 Xpub: "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", 800 Type: bchain.P2PKH, 801 Bip: "44", 802 ChangeIndexes: []uint32{0, 1}, 803 }, 804 }, 805 { 806 name: "ypub", 807 xpub: "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", 808 parser: btcMainParser, 809 want: &bchain.XpubDescriptor{ 810 XpubDescriptor: "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", 811 Xpub: "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", 812 Type: bchain.P2SHWPKH, 813 Bip: "49", 814 ChangeIndexes: []uint32{0, 1}, 815 }, 816 }, 817 { 818 name: "zpub", 819 xpub: "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", 820 parser: btcMainParser, 821 want: &bchain.XpubDescriptor{ 822 XpubDescriptor: "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", 823 Xpub: "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", 824 Type: bchain.P2WPKH, 825 Bip: "84", 826 ChangeIndexes: []uint32{0, 1}, 827 }, 828 }, 829 { 830 name: "sh(wpkh([5c9e228d/99'/0'/0']xpub/{122,123,4431}/*))", 831 xpub: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/*))", 832 parser: btcMainParser, 833 want: &bchain.XpubDescriptor{ 834 XpubDescriptor: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/*))", 835 Xpub: "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", 836 Type: bchain.P2SHWPKH, 837 Bip: "99", 838 ChangeIndexes: []uint32{122, 123, 4431}, 839 }, 840 }, 841 { 842 name: "sh(wpkh([5c9e228d/99'/0'/0']xpub/<122;123;4431>/*))", 843 xpub: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/<122;123;4431>/*))", 844 parser: btcMainParser, 845 want: &bchain.XpubDescriptor{ 846 XpubDescriptor: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/<122;123;4431>/*))", 847 Xpub: "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", 848 Type: bchain.P2SHWPKH, 849 Bip: "99", 850 ChangeIndexes: []uint32{122, 123, 4431}, 851 }, 852 }, 853 { 854 name: "pkh(xpub)", 855 xpub: "pkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)", 856 parser: btcMainParser, 857 want: &bchain.XpubDescriptor{ 858 XpubDescriptor: "pkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)", 859 Xpub: "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", 860 Type: bchain.P2PKH, 861 Bip: "44", 862 ChangeIndexes: []uint32{0, 1}, 863 }, 864 }, 865 { 866 name: "sh(wpkh(xpub))", 867 xpub: "sh(wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ))", 868 parser: btcMainParser, 869 want: &bchain.XpubDescriptor{ 870 XpubDescriptor: "sh(wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ))", 871 Xpub: "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", 872 Type: bchain.P2SHWPKH, 873 Bip: "49", 874 ChangeIndexes: []uint32{0, 1}, 875 }, 876 }, 877 { 878 name: "wpkh(xpub)", 879 xpub: "wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)", 880 parser: btcMainParser, 881 want: &bchain.XpubDescriptor{ 882 XpubDescriptor: "wpkh(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)", 883 Xpub: "xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ", 884 Type: bchain.P2WPKH, 885 Bip: "84", 886 ChangeIndexes: []uint32{0, 1}, 887 }, 888 }, 889 { 890 name: "xxx(xpub) error - unknown output script", 891 xpub: "xxx(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ)", 892 parser: btcMainParser, 893 wantErr: true, 894 }, 895 { 896 name: "sh(wpkh([5c9e228d/99'/0'/0']xpub/{0,123,4431}/1)) error - * in index is mandatory", 897 xpub: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/1))", 898 parser: btcMainParser, 899 wantErr: true, 900 }, 901 { 902 name: "sh(wpkh([5c9e228d/99'/0'/0']xpub/{0,123,4431}/1) error - path too long", 903 xpub: "sh(wpkh([5c9e228d/99'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/{122,123,4431}/1/*))", 904 parser: btcMainParser, 905 wantErr: true, 906 }, 907 } 908 for _, tt := range tests { 909 t.Run(tt.name, func(t *testing.T) { 910 got, err := tt.parser.ParseXpub(tt.xpub) 911 if (err != nil) != tt.wantErr { 912 t.Errorf("ParseXpub() error = %v, wantErr %v", err, tt.wantErr) 913 return 914 } 915 if err == nil { 916 if got.ExtKey == nil { 917 t.Errorf("ParseXpub() got nil ExtKey") 918 return 919 } 920 got.ExtKey = nil 921 if !reflect.DeepEqual(got, tt.want) { 922 t.Errorf("ParseXpub() = %+v, want %+v", got, tt.want) 923 } 924 } 925 }) 926 } 927 } 928 929 func TestDeriveAddressDescriptors(t *testing.T) { 930 btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518}) 931 btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198}) 932 type args struct { 933 xpub string 934 change uint32 935 indexes []uint32 936 parser *BitcoinParser 937 } 938 tests := []struct { 939 name string 940 args args 941 want []string 942 wantErr bool 943 }{ 944 { 945 name: "m/86'/1'/0'", 946 args: args{ 947 xpub: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/0/*)#4rqwxvej", 948 change: 0, 949 indexes: []uint32{0, 1, 10}, 950 parser: btcTestnetParser, 951 }, 952 want: []string{"tb1pswrqtykue8r89t9u4rprjs0gt4qzkdfuursfnvqaa3f2yql07zmq8s8a5u", "tb1p8tvmvsvhsee73rhym86wt435qrqm92psfsyhy6a3n5gw455znnpqm8wald", "tb1pqr4803xedptkvsr6ksed2m7fx780y3u8shnd0fqdupnc0w75262sl49kwz"}, 953 }, 954 { 955 name: "m/86'/0'/0'", 956 args: args{ 957 xpub: "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr", 958 change: 0, 959 indexes: []uint32{0, 1}, 960 parser: btcMainParser, 961 }, 962 want: []string{"bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr", "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh"}, 963 }, 964 { 965 name: "m/86'/0'/0'/1", 966 args: args{ 967 xpub: "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr", 968 change: 1, 969 indexes: []uint32{0}, 970 parser: btcMainParser, 971 }, 972 want: []string{"bc1p3qkhfews2uk44qtvauqyr2ttdsw7svhkl9nkm9s9c3x4ax5h60wqwruhk7"}, 973 }, 974 { 975 name: "m/44'/0'/0'", 976 args: args{ 977 xpub: "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", 978 change: 0, 979 indexes: []uint32{0, 1234}, 980 parser: btcMainParser, 981 }, 982 want: []string{"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA", "1P9w11dXAmG3QBjKLAvCsek8izs1iR2iFi"}, 983 }, 984 { 985 name: "m/49'/0'/0'", 986 args: args{ 987 xpub: "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", 988 change: 0, 989 indexes: []uint32{0, 1234}, 990 parser: btcMainParser, 991 }, 992 want: []string{"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf", "367meFzJ9KqDLm9PX6U8Z8RdmkSNBuxX8T"}, 993 }, 994 { 995 name: "m/84'/0'/0'", 996 args: args{ 997 xpub: "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", 998 change: 0, 999 indexes: []uint32{0, 1234}, 1000 parser: btcMainParser, 1001 }, 1002 want: []string{"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", "bc1q4nm6g46ujzyjaeusralaz2nfv2rf04jjfyamkw"}, 1003 }, 1004 } 1005 for _, tt := range tests { 1006 t.Run(tt.name, func(t *testing.T) { 1007 descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub) 1008 if err != nil { 1009 t.Errorf("ParseXpub() error = %v", err) 1010 return 1011 } 1012 got, err := tt.args.parser.DeriveAddressDescriptors(descriptor, tt.args.change, tt.args.indexes) 1013 if (err != nil) != tt.wantErr { 1014 t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr) 1015 return 1016 } 1017 gotAddresses := make([]string, len(got)) 1018 for i, ad := range got { 1019 aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad) 1020 if err != nil || len(aa) != 1 { 1021 t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err) 1022 return 1023 } 1024 gotAddresses[i] = aa[0] 1025 } 1026 if !reflect.DeepEqual(gotAddresses, tt.want) { 1027 t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want) 1028 } 1029 }) 1030 } 1031 } 1032 1033 func TestDeriveAddressDescriptorsFromTo(t *testing.T) { 1034 btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518}) 1035 btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198}) 1036 type args struct { 1037 xpub string 1038 change uint32 1039 fromIndex uint32 1040 toIndex uint32 1041 parser *BitcoinParser 1042 } 1043 tests := []struct { 1044 name string 1045 args args 1046 want []string 1047 wantErr bool 1048 }{ 1049 { 1050 name: "m/44'/0'/0'", 1051 args: args{ 1052 xpub: "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", 1053 change: 0, 1054 fromIndex: 0, 1055 toIndex: 1, 1056 parser: btcMainParser, 1057 }, 1058 want: []string{"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA"}, 1059 }, 1060 { 1061 name: "m/49'/0'/0'", 1062 args: args{ 1063 xpub: "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", 1064 change: 0, 1065 fromIndex: 0, 1066 toIndex: 1, 1067 parser: btcMainParser, 1068 }, 1069 want: []string{"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"}, 1070 }, 1071 { 1072 name: "m/84'/0'/0'", 1073 args: args{ 1074 xpub: "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", 1075 change: 0, 1076 fromIndex: 0, 1077 toIndex: 1, 1078 parser: btcMainParser, 1079 }, 1080 want: []string{"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"}, 1081 }, 1082 { 1083 name: "m/86'/0'/0'", 1084 args: args{ 1085 xpub: "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr", 1086 change: 0, 1087 fromIndex: 0, 1088 toIndex: 1, 1089 parser: btcMainParser, 1090 }, 1091 want: []string{"bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr"}, 1092 }, 1093 { 1094 name: "m/49'/1'/0'", 1095 args: args{ 1096 xpub: "upub5DR1Mg5nykixzYjFXWW5GghAU7dDqoPVJ2jrqFbL8sJ7Hs7jn69MP7KBnnmxn88GeZtnH8PRKV9w5MMSFX8AdEAoXY8Qd8BJPoXtpMeHMxJ", 1097 change: 0, 1098 fromIndex: 0, 1099 toIndex: 10, 1100 parser: btcTestnetParser, 1101 }, 1102 want: []string{"2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp", "2Mt7P2BAfE922zmfXrdcYTLyR7GUvbwSEns", "2N6aUMgQk8y1zvoq6FeWFyotyj75WY9BGsu", "2NA7tbZWM9BcRwBuebKSQe2xbhhF1paJwBM", "2N8RZMzvrUUnpLmvACX9ysmJ2MX3GK5jcQM", "2MvUUSiQZDSqyeSdofKX9KrSCio1nANPDTe", "2NBXaWu1HazjoUVgrXgcKNoBLhtkkD9Gmet", "2N791Ttf89tMVw2maj86E1Y3VgxD9Mc7PU7", "2NCJmwEq8GJm8t8GWWyBXAfpw7F2qZEVP5Y", "2NEgW71hWKer2XCSA8ZCC2VnWpB77L6bk68"}, 1103 }, 1104 } 1105 for _, tt := range tests { 1106 t.Run(tt.name, func(t *testing.T) { 1107 descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub) 1108 if err != nil { 1109 t.Errorf("ParseXpub() error = %v", err) 1110 return 1111 } 1112 got, err := tt.args.parser.DeriveAddressDescriptorsFromTo(descriptor, tt.args.change, tt.args.fromIndex, tt.args.toIndex) 1113 if (err != nil) != tt.wantErr { 1114 t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr) 1115 return 1116 } 1117 gotAddresses := make([]string, len(got)) 1118 for i, ad := range got { 1119 aa, _, err := tt.args.parser.GetAddressesFromAddrDesc(ad) 1120 if err != nil || len(aa) != 1 { 1121 t.Errorf("DeriveAddressDescriptorsFromTo() got incorrect address descriptor %v, error %v", ad, err) 1122 return 1123 } 1124 gotAddresses[i] = aa[0] 1125 } 1126 if !reflect.DeepEqual(gotAddresses, tt.want) { 1127 t.Errorf("DeriveAddressDescriptorsFromTo() = %v, want %v", gotAddresses, tt.want) 1128 } 1129 }) 1130 } 1131 } 1132 1133 func BenchmarkDeriveAddressDescriptorsFromToXpub(b *testing.B) { 1134 btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518}) 1135 for i := 0; i < b.N; i++ { 1136 descriptor, _ := btcMainParser.ParseXpub("xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj") 1137 btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100) 1138 } 1139 } 1140 1141 func BenchmarkDeriveAddressDescriptorsFromToYpub(b *testing.B) { 1142 btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518}) 1143 for i := 0; i < b.N; i++ { 1144 descriptor, _ := btcMainParser.ParseXpub("ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP") 1145 btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100) 1146 } 1147 } 1148 1149 func BenchmarkDeriveAddressDescriptorsFromToZpub(b *testing.B) { 1150 btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518}) 1151 for i := 0; i < b.N; i++ { 1152 descriptor, _ := btcMainParser.ParseXpub("zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs") 1153 btcMainParser.DeriveAddressDescriptorsFromTo(descriptor, 1, 0, 100) 1154 } 1155 } 1156 1157 func TestBitcoinParser_DerivationBasePath(t *testing.T) { 1158 btcMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, XPubMagicSegwitP2sh: 77429938, XPubMagicSegwitNative: 78792518, Slip44: 0}) 1159 btcTestnetParser := NewBitcoinParser(GetChainParams("test"), &Configuration{XPubMagic: 70617039, XPubMagicSegwitP2sh: 71979618, XPubMagicSegwitNative: 73342198, Slip44: 1}) 1160 zecMainParser := NewBitcoinParser(GetChainParams("main"), &Configuration{XPubMagic: 76067358, Slip44: 133}) 1161 type args struct { 1162 xpub string 1163 parser *BitcoinParser 1164 } 1165 tests := []struct { 1166 name string 1167 args args 1168 want string 1169 wantErr bool 1170 }{ 1171 { 1172 name: "m/86'/1'/0'", 1173 args: args{ 1174 xpub: "tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/0/*)#4rqwxvej", 1175 parser: btcTestnetParser, 1176 }, 1177 want: "m/86'/1'/0'", 1178 }, 1179 { 1180 name: "m/86'/0'/0'", 1181 args: args{ 1182 xpub: "tr([5c9e228d/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#d8jj22qr", 1183 parser: btcMainParser, 1184 }, 1185 want: "m/86'/0'/0'", 1186 }, 1187 { 1188 name: "m/84'/0'/0'", 1189 args: args{ 1190 xpub: "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", 1191 parser: btcMainParser, 1192 }, 1193 want: "m/84'/0'/0'", 1194 }, 1195 { 1196 name: "m/49'/0'/55 - not hardened account", 1197 args: args{ 1198 xpub: "ypub6XKbB5DJRAbW4TRJLp4uXQXG3ob5BtByXsNZFBjq9qcbzrczjVXfCz5cEo1SFDexmeWRnbCMDaRgaW4m9d2nBaa8FvUQCu3n9G1UBR8WhbT", 1199 parser: btcMainParser, 1200 }, 1201 want: "m/49'/0'/55", 1202 }, 1203 { 1204 name: "m/49'/0' - incomplete path, without account", 1205 args: args{ 1206 xpub: "ypub6UzM8PUqxcSoqC9gumfoiFhE8Qt84HbGpCD4eVJfJAojXTVtBxeddvTWJGJhGoaVBNJLmEgMdLXHgaLVJa4xEvk2tcokkdZhFdkxMLUE9sB", 1207 parser: btcMainParser, 1208 }, 1209 want: "unknown/0'", 1210 }, 1211 { 1212 name: "m/49'/1'/0'", 1213 args: args{ 1214 xpub: "upub5DR1Mg5nykixzYjFXWW5GghAU7dDqoPVJ2jrqFbL8sJ7Hs7jn69MP7KBnnmxn88GeZtnH8PRKV9w5MMSFX8AdEAoXY8Qd8BJPoXtpMeHMxJ", 1215 parser: btcTestnetParser, 1216 }, 1217 want: "m/49'/1'/0'", 1218 }, 1219 { 1220 name: "m/44'/133'/12'", 1221 args: args{ 1222 xpub: "xpub6CQdEahwhKRTLYpP6cyb7ZaGb3r4tVdyPX6dC1PfrNuByrCkWDgUkmpD28UdV9QccKgY1ZiAbGv1Fakcg2LxdFVSTNKHcjdRjqhjPK8Trkb", 1223 parser: zecMainParser, 1224 }, 1225 want: "m/44'/133'/12'", 1226 }, 1227 } 1228 for _, tt := range tests { 1229 t.Run(tt.name, func(t *testing.T) { 1230 descriptor, err := tt.args.parser.ParseXpub(tt.args.xpub) 1231 if err != nil { 1232 t.Errorf("ParseXpub() error = %v", err) 1233 return 1234 } 1235 got, err := tt.args.parser.DerivationBasePath(descriptor) 1236 if (err != nil) != tt.wantErr { 1237 t.Errorf("BitcoinParser.DerivationBasePath() error = %v, wantErr %v", err, tt.wantErr) 1238 return 1239 } 1240 if got != tt.want { 1241 t.Errorf("BitcoinParser.DerivationBasePath() = %v, want %v", got, tt.want) 1242 } 1243 }) 1244 } 1245 }