github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/nuls/nulsparser_test.go (about) 1 //go:build unittest 2 3 package nuls 4 5 import ( 6 "encoding/hex" 7 "math/big" 8 "reflect" 9 "testing" 10 11 "github.com/ethereum/go-ethereum/common/hexutil" 12 "github.com/martinboehm/btcutil/hdkeychain" 13 "github.com/trezor/blockbook/bchain" 14 "github.com/trezor/blockbook/bchain/coins/btc" 15 "github.com/trezor/blockbook/common" 16 ) 17 18 var ( 19 testTx1, testTx2 bchain.Tx 20 21 testTxPacked1 = "0001e240daadfbe7931e000000007b22686578223a22222c2274786964223a223030323036626231323431303861356664393865383238623138316666303162393237633063366234373764343531326266656638346366353266306663326136613161222c2276657273696f6e223a312c226c6f636b74696d65223a302c2276696e223a5b7b22636f696e62617365223a22222c2274786964223a223030323035343537616230373033623164313034363264343334373034386330626233353634653430663537616531663632353136393539343364653161633831306130222c22766f7574223a302c22736372697074536967223a7b22686578223a22227d2c2273657175656e6365223a302c22616464726573736573223a5b224e736535334d77524c424a31575555365365644d485141466643507442377734225d7d5d2c22766f7574223a5b7b2256616c7565536174223a3339393939393030303030302c2276616c7565223a302c226e223a302c227363726970745075624b6579223a7b22686578223a224e7365347a705a4873557555376835796d7632387063476277486a75336a6f56222c22616464726573736573223a5b224e7365347a705a4873557555376835796d7632387063476277486a75336a6f56225d7d7d5d2c22626c6f636b74696d65223a313535323335373834343137357d" 22 testTxPacked2 = "0007c91adaadfbb89946000000007b22686578223a22222c2274786964223a223030323037386139386633383163373134613036386436303565346265316565323139353438353736313165303938616262636333663530633536383066386164326535222c2276657273696f6e223a312c226c6f636b74696d65223a302c2276696e223a5b7b22636f696e62617365223a22222c2274786964223a223030323037613430646334623661633430376434396133633333616137353462623466303565343565353763323438313162313437653762663363616630363361383233222c22766f7574223a312c22736372697074536967223a7b22686578223a22227d2c2273657175656e6365223a302c22616464726573736573223a5b224e73653131397a326f53444a596b466b786d775944695974506642654e6b7169225d7d5d2c22766f7574223a5b7b2256616c7565536174223a3430303030303030303030302c2276616c7565223a302c226e223a302c227363726970745075624b6579223a7b22686578223a224e736534696b6a45383867324267734e7773737754646b53776953724b6a6a53222c22616464726573736573223a5b224e736534696b6a45383867324267734e7773737754646b53776953724b6a6a53225d7d7d2c7b2256616c7565536174223a373238363536353537303030302c2276616c7565223a302c226e223a312c227363726970745075624b6579223a7b22686578223a224e73653131397a326f53444a596b466b786d775944695974506642654e6b7169222c22616464726573736573223a5b224e73653131397a326f53444a596b466b786d775944695974506642654e6b7169225d7d7d5d2c22626c6f636b74696d65223a313535323335373435393535357d" 23 ) 24 25 func init() { 26 testTx1 = bchain.Tx{ 27 Hex: "", 28 Blocktime: 1552357844175, 29 Txid: "00206bb124108a5fd98e828b181ff01b927c0c6b477d4512bfef84cf52f0fc2a6a1a", 30 LockTime: 0, 31 Version: 1, 32 Vin: []bchain.Vin{ 33 { 34 Txid: "00205457ab0703b1d10462d4347048c0bb3564e40f57ae1f6251695943de1ac810a0", 35 Vout: 0, 36 Sequence: 0, 37 Addresses: []string{ 38 "Nse53MwRLBJ1WUU6SedMHQAFfCPtB7w4", 39 }, 40 }, 41 }, 42 Vout: []bchain.Vout{ 43 { 44 ValueSat: *big.NewInt(399999000000), 45 N: 0, 46 JsonValue: common.JSONNumber("0"), 47 ScriptPubKey: bchain.ScriptPubKey{ 48 Hex: "Nse4zpZHsUuU7h5ymv28pcGbwHju3joV", 49 Addresses: []string{ 50 "Nse4zpZHsUuU7h5ymv28pcGbwHju3joV", 51 }, 52 }, 53 }, 54 }, 55 //CoinSpecificData: []string{}, 56 } 57 58 testTx2 = bchain.Tx{ 59 Hex: "", 60 Blocktime: 1552357459555, 61 Txid: "002078a98f381c714a068d605e4be1ee21954857611e098abbcc3f50c5680f8ad2e5", 62 LockTime: 0, 63 Version: 1, 64 Vin: []bchain.Vin{ 65 { 66 Txid: "00207a40dc4b6ac407d49a3c33aa754bb4f05e45e57c24811b147e7bf3caf063a823", 67 Vout: 1, 68 Sequence: 0, 69 Addresses: []string{ 70 "Nse119z2oSDJYkFkxmwYDiYtPfBeNkqi", 71 }, 72 }, 73 }, 74 Vout: []bchain.Vout{ 75 { 76 ValueSat: *big.NewInt(400000000000), 77 N: 0, 78 JsonValue: common.JSONNumber("0"), 79 ScriptPubKey: bchain.ScriptPubKey{ 80 Hex: "Nse4ikjE88g2BgsNwsswTdkSwiSrKjjS", 81 Addresses: []string{ 82 "Nse4ikjE88g2BgsNwsswTdkSwiSrKjjS", 83 }, 84 }, 85 }, 86 { 87 ValueSat: *big.NewInt(7286565570000), 88 N: 1, 89 JsonValue: common.JSONNumber("0"), 90 ScriptPubKey: bchain.ScriptPubKey{ 91 Hex: "Nse119z2oSDJYkFkxmwYDiYtPfBeNkqi", 92 Addresses: []string{ 93 "Nse119z2oSDJYkFkxmwYDiYtPfBeNkqi", 94 }, 95 }, 96 }, 97 }, 98 //CoinSpecificData: []string{}, 99 } 100 } 101 102 func TestGetAddrDescFromAddress(t *testing.T) { 103 type args struct { 104 address string 105 } 106 tests := []struct { 107 name string 108 args args 109 want string 110 wantErr bool 111 }{ 112 { 113 name: "P2PKH", 114 args: args{address: "Nse4j39uEMuxx5j577h3K2MDLAQ64JZN"}, 115 want: "042301ac78cd3eb193287e2c59e4cbd765c5c47d432c2fa1", 116 wantErr: false, 117 }, 118 { 119 name: "P2PKH", 120 args: args{address: "Nse2e7U7nmGT8UHsvQ7JfksLtWwoLwrd"}, 121 want: "0423018a90e66a64318f6af6d673487a6560f5686fd26a2e", 122 wantErr: false, 123 }, 124 { 125 name: "P2PKH", 126 args: args{address: "NsdvMEP57nzxmBa5z18rx9sQsLgUfNtw"}, 127 want: "04230124422cfe426573e476fd45d7c2a43a75a0b6b8c478", 128 wantErr: false, 129 }, 130 } 131 parser := NewNulsParser(GetChainParams("main"), &btc.Configuration{}) 132 133 for _, tt := range tests { 134 t.Run(tt.name, func(t *testing.T) { 135 got, err := parser.GetAddrDescFromAddress(tt.args.address) 136 if (err != nil) != tt.wantErr { 137 t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr) 138 return 139 } 140 h := hex.EncodeToString(got) 141 if !reflect.DeepEqual(h, tt.want) { 142 t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want) 143 } 144 }) 145 } 146 } 147 148 func TestGetAddrDescFromVout(t *testing.T) { 149 type args struct { 150 vout bchain.Vout 151 } 152 tests := []struct { 153 name string 154 args args 155 want string 156 wantErr bool 157 }{ 158 { 159 name: "P2PK", 160 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "Nse4j39uEMuxx5j577h3K2MDLAQ64JZN"}}}, 161 want: "042301ac78cd3eb193287e2c59e4cbd765c5c47d432c2fa1", 162 wantErr: false, 163 }, 164 { 165 name: "P2PK", 166 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "Nse2e7U7nmGT8UHsvQ7JfksLtWwoLwrd"}}}, 167 want: "0423018a90e66a64318f6af6d673487a6560f5686fd26a2e", 168 wantErr: false, 169 }, 170 { 171 name: "P2PK", 172 args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "NsdvMEP57nzxmBa5z18rx9sQsLgUfNtw"}}}, 173 want: "04230124422cfe426573e476fd45d7c2a43a75a0b6b8c478", 174 wantErr: false, 175 }, 176 } 177 parser := NewNulsParser(GetChainParams("main"), &btc.Configuration{}) 178 179 for _, tt := range tests { 180 t.Run(tt.name, func(t *testing.T) { 181 got, err := parser.GetAddrDescFromVout(&tt.args.vout) 182 if (err != nil) != tt.wantErr { 183 t.Errorf("GetAddrDescFromVout() error = %v, wantErr %v", err, tt.wantErr) 184 return 185 } 186 h := hex.EncodeToString(got) 187 if !reflect.DeepEqual(h, tt.want) { 188 t.Errorf("GetAddrDescFromVout() = %v, want %v", h, tt.want) 189 } 190 }) 191 } 192 } 193 194 func TestGetAddressesFromAddrDesc(t *testing.T) { 195 type args struct { 196 script string 197 } 198 tests := []struct { 199 name string 200 args args 201 want []string 202 want2 bool 203 wantErr bool 204 }{ 205 { 206 name: "P2PKH", 207 args: args{script: "042301ac78cd3eb193287e2c59e4cbd765c5c47d432c2fa1"}, 208 want: []string{"Nse4j39uEMuxx5j577h3K2MDLAQ64JZN"}, 209 want2: true, 210 wantErr: false, 211 }, 212 { 213 name: "P2PKH", 214 args: args{script: "0423018a90e66a64318f6af6d673487a6560f5686fd26a2e"}, 215 want: []string{"Nse2e7U7nmGT8UHsvQ7JfksLtWwoLwrd"}, 216 want2: true, 217 wantErr: false, 218 }, 219 { 220 name: "P2PKH", 221 args: args{script: "04230124422cfe426573e476fd45d7c2a43a75a0b6b8c478"}, 222 want: []string{"NsdvMEP57nzxmBa5z18rx9sQsLgUfNtw"}, 223 want2: true, 224 wantErr: false, 225 }, 226 } 227 228 parser := NewNulsParser(GetChainParams("main"), &btc.Configuration{}) 229 230 for _, tt := range tests { 231 t.Run(tt.name, func(t *testing.T) { 232 b, _ := hex.DecodeString(tt.args.script) 233 got, got2, err := parser.GetAddressesFromAddrDesc(b) 234 if (err != nil) != tt.wantErr { 235 t.Errorf("GetAddressesFromAddrDesc() error = %v, wantErr %v", err, tt.wantErr) 236 return 237 } 238 if !reflect.DeepEqual(got, tt.want) { 239 t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.want) 240 } 241 if !reflect.DeepEqual(got2, tt.want2) { 242 t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.want2) 243 } 244 }) 245 } 246 } 247 248 func TestPackTx(t *testing.T) { 249 type args struct { 250 tx bchain.Tx 251 height uint32 252 blockTime int64 253 parser *NulsParser 254 } 255 tests := []struct { 256 name string 257 args args 258 want string 259 wantErr bool 260 }{ 261 { 262 name: "test-1", 263 args: args{ 264 tx: testTx1, 265 height: 123456, 266 blockTime: 1552357844175, 267 parser: NewNulsParser(GetChainParams("main"), &btc.Configuration{}), 268 }, 269 want: testTxPacked1, 270 wantErr: false, 271 }, 272 { 273 name: "test-2", 274 args: args{ 275 tx: testTx2, 276 height: 510234, 277 blockTime: 1552357459555, 278 parser: NewNulsParser(GetChainParams("main"), &btc.Configuration{}), 279 }, 280 want: testTxPacked2, 281 wantErr: false, 282 }, 283 } 284 for _, tt := range tests { 285 t.Run(tt.name, func(t *testing.T) { 286 got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime) 287 if (err != nil) != tt.wantErr { 288 t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr) 289 return 290 } 291 h := hex.EncodeToString(got) 292 if !reflect.DeepEqual(h, tt.want) { 293 t.Errorf("packTx() = %v, want %v", h, tt.want) 294 } 295 }) 296 } 297 } 298 299 func TestUnpackTx(t *testing.T) { 300 type args struct { 301 packedTx string 302 parser *NulsParser 303 } 304 tests := []struct { 305 name string 306 args args 307 want *bchain.Tx 308 want1 uint32 309 wantErr bool 310 }{ 311 { 312 name: "test-1", 313 args: args{ 314 packedTx: testTxPacked1, 315 parser: NewNulsParser(GetChainParams("main"), &btc.Configuration{}), 316 }, 317 want: &testTx1, 318 want1: 123456, 319 wantErr: false, 320 }, 321 { 322 name: "test-2", 323 args: args{ 324 packedTx: testTxPacked2, 325 parser: NewNulsParser(GetChainParams("main"), &btc.Configuration{}), 326 }, 327 want: &testTx2, 328 want1: 510234, 329 wantErr: false, 330 }, 331 } 332 for _, tt := range tests { 333 t.Run(tt.name, func(t *testing.T) { 334 b, _ := hex.DecodeString(tt.args.packedTx) 335 got, got1, err := tt.args.parser.UnpackTx(b) 336 if (err != nil) != tt.wantErr { 337 t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr) 338 return 339 } 340 if !reflect.DeepEqual(got, tt.want) { 341 t.Errorf("unpackTx() got = %+v, want %+v", got, tt.want) 342 } 343 if got1 != tt.want1 { 344 t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1) 345 } 346 }) 347 } 348 } 349 350 func TestDeriveAddressDescriptorsFromTo(t *testing.T) { 351 352 parser := NewNulsParser(GetChainParams("main"), &btc.Configuration{}) 353 354 // test xpub xprv math ,and get private key 355 xprv := "xprv9yEvwSfPanK5gLYVnYvNyF2CEWJx1RsktQtKDeT6jnCnqASBiPCvFYHFSApXv39bZbF6hRaha1kWQBVhN1xjo7NHuhAn5uUfzy79TBuGiHh" 356 xpub := "xpub6CEHLxCHR9sNtpcxtaTPLNxvnY9SQtbcFdov22riJ7jmhxmLFvXAoLbjHSzwXwNNuxC1jUP6tsHzFV9rhW9YKELfmR9pJaKFaM8C3zMPgjw" 357 extKey, err := hdkeychain.NewKeyFromString(xprv, parser.Params.Base58CksumHasher) 358 if err != nil { 359 t.Errorf("DeriveAddressDescriptorsFromTo() error = %v", err) 360 return 361 } 362 changeExtKey, err := extKey.Derive(0) 363 if err != nil { 364 t.Errorf("DeriveAddressDescriptorsFromTo() error = %v", err) 365 return 366 } 367 368 key1, _ := changeExtKey.Derive(0) 369 priKey1, _ := key1.ECPrivKey() 370 wantPriKey1 := "0x995c98115809359eb57a5e179558faddd55ef88f88e5cf58617a5f9f3d6bb3a1" 371 if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey1), priKey1.Serialize()) { 372 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPriKey1, hexutil.Encode(priKey1.Serialize())) 373 return 374 } 375 pubKey1, _ := key1.ECPubKey() 376 wantPubKey1 := "0x028855d37e8b1d2760289ea51996df05f3297d86fae4e113aea696a0f02a420ae2" 377 if !reflect.DeepEqual(hexutil.MustDecode(wantPubKey1), pubKey1.SerializeCompressed()) { 378 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPubKey1, hexutil.Encode(pubKey1.SerializeCompressed())) 379 return 380 } 381 382 key2, _ := changeExtKey.Derive(1) 383 priKey2, _ := key2.ECPrivKey() 384 wantPriKey2 := "0x0f65dee42d3c974c1a4bcc79f141be89715dc8d6406faa9ad4f1f55ca95fabc8" 385 if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey2), priKey2.Serialize()) { 386 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPriKey2, hexutil.Encode(priKey2.Serialize())) 387 return 388 } 389 pubKey2, _ := key2.ECPubKey() 390 wantPubKey2 := "0x0216f460ea59194464a6c981560e3f52899203496ed8a20f8f9a57a9225d841293" 391 if !reflect.DeepEqual(hexutil.MustDecode(wantPubKey2), pubKey2.SerializeCompressed()) { 392 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPubKey2, hexutil.Encode(pubKey2.SerializeCompressed())) 393 return 394 } 395 396 key3, _ := changeExtKey.Derive(2) 397 priKey3, _ := key3.ECPrivKey() 398 wantPriKey3 := "0x6fd98d1d9c3f3ac1ff61bbf3f20e89f00ffa8d43a554f2a7d73fd464b6666f45" 399 if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey3), priKey3.Serialize()) { 400 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPriKey3, hexutil.Encode(priKey3.Serialize())) 401 return 402 } 403 pubKey3, _ := key3.ECPubKey() 404 wantPubKey3 := "0x0327ef15c2eaf99365610d6ef89d9ad1e89d1ddf888fc0ec7eb8a94d97153ee482" 405 if !reflect.DeepEqual(hexutil.MustDecode(wantPubKey3), pubKey3.SerializeCompressed()) { 406 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPubKey3, hexutil.Encode(pubKey3.SerializeCompressed())) 407 return 408 } 409 410 key4, _ := changeExtKey.Derive(3) 411 priKey4, _ := key4.ECPrivKey() 412 wantPriKey4 := "0x21412d9e33aba493faf4bc7d408ed5290bea5b36a7beec554b858051f8d4bff3" 413 if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey4), priKey4.Serialize()) { 414 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPriKey4, hexutil.Encode(priKey4.Serialize())) 415 return 416 } 417 pubKey4, _ := key4.ECPubKey() 418 wantPubKey4 := "0x02a73aebd08c6f70fa97f616b1c0b63756efe9eb070a14628de3d850b2b970a9a7" 419 if !reflect.DeepEqual(hexutil.MustDecode(wantPubKey4), pubKey4.SerializeCompressed()) { 420 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPubKey4, hexutil.Encode(pubKey4.SerializeCompressed())) 421 return 422 } 423 424 key5, _ := changeExtKey.Derive(4) 425 priKey5, _ := key5.ECPrivKey() 426 wantPriKey5 := "0xdc3d290e32a4e0f38bc26c25a78ceb1c8779110883d9cb0be54629043c1f8724" 427 if !reflect.DeepEqual(hexutil.MustDecode(wantPriKey5), priKey5.Serialize()) { 428 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPriKey5, hexutil.Encode(priKey5.Serialize())) 429 return 430 } 431 pubKey5, _ := key5.ECPubKey() 432 wantPubKey5 := "0x02f87eb70b985a857d7238bc9423dab7d5930f3fcfc2118ccac0634a9342b9d324" 433 if !reflect.DeepEqual(hexutil.MustDecode(wantPubKey5), pubKey5.SerializeCompressed()) { 434 t.Errorf("DeriveAddressDescriptorsFromTo() %v, want %v", wantPubKey5, hexutil.Encode(pubKey5.SerializeCompressed())) 435 return 436 } 437 438 type args struct { 439 xpub string 440 change uint32 441 fromIndex uint32 442 toIndex uint32 443 } 444 tests := []struct { 445 name string 446 args args 447 want []string 448 wantErr bool 449 }{ 450 { 451 name: "test-xpub", 452 args: args{ 453 xpub: xpub, 454 change: 0, 455 fromIndex: 0, 456 toIndex: 5, 457 }, 458 want: []string{ 459 "NsdtwhD8hb8H72J7FyQpGta2sqLngrXZ", 460 "Nse51sBAzRTVtm48wYQLb4TH7MGAHAER", 461 "NsdvoFSwfh1oW238SFM6p5wL4J834Gv2", 462 "Nse4wVWsJ4v3jPcpE4vRkAiZLFyQSNKd", 463 "Nse5NzUcZybsvFQeNgqfuWmmmwCfhdxF", 464 }, 465 wantErr: false, 466 }, 467 { 468 name: "test-xprv", 469 args: args{ 470 xpub: xprv, 471 change: 0, 472 fromIndex: 0, 473 toIndex: 5, 474 }, 475 want: []string{ 476 "NsdtwhD8hb8H72J7FyQpGta2sqLngrXZ", 477 "Nse51sBAzRTVtm48wYQLb4TH7MGAHAER", 478 "NsdvoFSwfh1oW238SFM6p5wL4J834Gv2", 479 "Nse4wVWsJ4v3jPcpE4vRkAiZLFyQSNKd", 480 "Nse5NzUcZybsvFQeNgqfuWmmmwCfhdxF", 481 }, 482 wantErr: false, 483 }, 484 } 485 486 for _, tt := range tests { 487 t.Run(tt.name, func(t *testing.T) { 488 descriptor, err := parser.ParseXpub(tt.args.xpub) 489 if err != nil { 490 t.Errorf("ParseXpub() error = %v", err) 491 return 492 } 493 got, err := parser.DeriveAddressDescriptorsFromTo(descriptor, tt.args.change, tt.args.fromIndex, tt.args.toIndex) 494 if (err != nil) != tt.wantErr { 495 t.Errorf("DeriveAddressDescriptorsFromTo() error = %v, wantErr %v", err, tt.wantErr) 496 return 497 } 498 if len(got) != len(tt.want) { 499 t.Errorf("DeriveAddressDescriptorsFromTo() result count = %v, want %v", len(got), len(tt.want)) 500 return 501 } 502 503 for i, add := range tt.want { 504 addStrs, ok, error := parser.GetAddressesFromAddrDesc(got[i]) 505 if !ok || error != nil { 506 t.Errorf("DeriveAddressDescriptorsFromTo() fail %v - %v , %v", i, ok, error) 507 return 508 } 509 if len(addStrs) != 1 { 510 t.Errorf("DeriveAddressDescriptorsFromTo() len(adds) != 1, %v", addStrs) 511 return 512 } 513 if !reflect.DeepEqual(addStrs[0], add) { 514 t.Errorf("DeriveAddressDescriptorsFromTo() of index %v = %v, want %v", i, addStrs, add) 515 return 516 } 517 } 518 }) 519 } 520 521 }