github.com/dim4egster/coreth@v0.10.2/plugin/evm/import_tx_test.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package evm 5 6 import ( 7 "math/big" 8 "testing" 9 10 "github.com/dim4egster/coreth/params" 11 "github.com/ethereum/go-ethereum/common" 12 13 "github.com/dim4egster/qmallgo/chains/atomic" 14 "github.com/dim4egster/qmallgo/ids" 15 "github.com/dim4egster/qmallgo/utils/constants" 16 "github.com/dim4egster/qmallgo/utils/crypto" 17 "github.com/dim4egster/qmallgo/vms/components/avax" 18 "github.com/dim4egster/qmallgo/vms/secp256k1fx" 19 ) 20 21 // createImportTxOptions adds a UTXO to shared memory and generates a list of import transactions sending this UTXO 22 // to each of the three test keys (conflicting transactions) 23 func createImportTxOptions(t *testing.T, vm *VM, sharedMemory *atomic.Memory) []*Tx { 24 utxo := &avax.UTXO{ 25 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 26 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 27 Out: &secp256k1fx.TransferOutput{ 28 Amt: uint64(50000000), 29 OutputOwners: secp256k1fx.OutputOwners{ 30 Threshold: 1, 31 Addrs: []ids.ShortID{testKeys[0].PublicKey().Address()}, 32 }, 33 }, 34 } 35 utxoBytes, err := vm.codec.Marshal(codecVersion, utxo) 36 if err != nil { 37 t.Fatal(err) 38 } 39 40 xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID) 41 inputID := utxo.InputID() 42 if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{ 43 Key: inputID[:], 44 Value: utxoBytes, 45 Traits: [][]byte{ 46 testKeys[0].PublicKey().Address().Bytes(), 47 }, 48 }}}}); err != nil { 49 t.Fatal(err) 50 } 51 52 importTxs := make([]*Tx, 0, 3) 53 for _, ethAddr := range testEthAddrs { 54 importTx, err := vm.newImportTx(vm.ctx.XChainID, ethAddr, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]}) 55 if err != nil { 56 t.Fatal(err) 57 } 58 importTxs = append(importTxs, importTx) 59 } 60 61 return importTxs 62 } 63 64 func TestImportTxVerify(t *testing.T) { 65 ctx := NewContext() 66 67 var importAmount uint64 = 10000000 68 txID := ids.GenerateTestID() 69 importTx := &UnsignedImportTx{ 70 NetworkID: ctx.NetworkID, 71 BlockchainID: ctx.ChainID, 72 SourceChain: ctx.XChainID, 73 ImportedInputs: []*avax.TransferableInput{ 74 { 75 UTXOID: avax.UTXOID{ 76 TxID: txID, 77 OutputIndex: uint32(0), 78 }, 79 Asset: avax.Asset{ID: ctx.AVAXAssetID}, 80 In: &secp256k1fx.TransferInput{ 81 Amt: importAmount, 82 Input: secp256k1fx.Input{ 83 SigIndices: []uint32{0}, 84 }, 85 }, 86 }, 87 { 88 UTXOID: avax.UTXOID{ 89 TxID: txID, 90 OutputIndex: uint32(1), 91 }, 92 Asset: avax.Asset{ID: ctx.AVAXAssetID}, 93 In: &secp256k1fx.TransferInput{ 94 Amt: importAmount, 95 Input: secp256k1fx.Input{ 96 SigIndices: []uint32{0}, 97 }, 98 }, 99 }, 100 }, 101 Outs: []EVMOutput{ 102 { 103 Address: testEthAddrs[0], 104 Amount: importAmount - params.AvalancheAtomicTxFee, 105 AssetID: ctx.AVAXAssetID, 106 }, 107 { 108 Address: testEthAddrs[1], 109 Amount: importAmount, 110 AssetID: ctx.AVAXAssetID, 111 }, 112 }, 113 } 114 115 // // Sort the inputs and outputs to ensure the transaction is canonical 116 avax.SortTransferableInputs(importTx.ImportedInputs) 117 SortEVMOutputs(importTx.Outs) 118 119 tests := map[string]atomicTxVerifyTest{ 120 "nil tx": { 121 generate: func(t *testing.T) UnsignedAtomicTx { 122 var importTx *UnsignedImportTx 123 return importTx 124 }, 125 ctx: ctx, 126 rules: apricotRulesPhase0, 127 expectedErr: errNilTx.Error(), 128 }, 129 "valid import tx": { 130 generate: func(t *testing.T) UnsignedAtomicTx { 131 return importTx 132 }, 133 ctx: ctx, 134 rules: apricotRulesPhase0, 135 expectedErr: "", // Expect this transaction to be valid in Apricot Phase 0 136 }, 137 "valid import tx banff": { 138 generate: func(t *testing.T) UnsignedAtomicTx { 139 return importTx 140 }, 141 ctx: ctx, 142 rules: banffRules, 143 expectedErr: "", // Expect this transaction to be valid in Banff 144 }, 145 "invalid network ID": { 146 generate: func(t *testing.T) UnsignedAtomicTx { 147 tx := *importTx 148 tx.NetworkID++ 149 return &tx 150 }, 151 ctx: ctx, 152 rules: apricotRulesPhase0, 153 expectedErr: errWrongNetworkID.Error(), 154 }, 155 "invalid blockchain ID": { 156 generate: func(t *testing.T) UnsignedAtomicTx { 157 tx := *importTx 158 tx.BlockchainID = ids.GenerateTestID() 159 return &tx 160 }, 161 ctx: ctx, 162 rules: apricotRulesPhase0, 163 expectedErr: errWrongBlockchainID.Error(), 164 }, 165 "P-chain source before AP5": { 166 generate: func(t *testing.T) UnsignedAtomicTx { 167 tx := *importTx 168 tx.SourceChain = constants.PlatformChainID 169 return &tx 170 }, 171 ctx: ctx, 172 rules: apricotRulesPhase0, 173 expectedErr: errWrongChainID.Error(), 174 }, 175 "P-chain source after AP5": { 176 generate: func(t *testing.T) UnsignedAtomicTx { 177 tx := *importTx 178 tx.SourceChain = constants.PlatformChainID 179 return &tx 180 }, 181 ctx: ctx, 182 rules: apricotRulesPhase5, 183 }, 184 "invalid source chain ID": { 185 generate: func(t *testing.T) UnsignedAtomicTx { 186 tx := *importTx 187 tx.SourceChain = ids.GenerateTestID() 188 return &tx 189 }, 190 ctx: ctx, 191 rules: apricotRulesPhase5, 192 expectedErr: errWrongChainID.Error(), 193 }, 194 "no inputs": { 195 generate: func(t *testing.T) UnsignedAtomicTx { 196 tx := *importTx 197 tx.ImportedInputs = nil 198 return &tx 199 }, 200 ctx: ctx, 201 rules: apricotRulesPhase0, 202 expectedErr: errNoImportInputs.Error(), 203 }, 204 "inputs sorted incorrectly": { 205 generate: func(t *testing.T) UnsignedAtomicTx { 206 tx := *importTx 207 tx.ImportedInputs = []*avax.TransferableInput{ 208 tx.ImportedInputs[1], 209 tx.ImportedInputs[0], 210 } 211 return &tx 212 }, 213 ctx: ctx, 214 rules: apricotRulesPhase0, 215 expectedErr: errInputsNotSortedUnique.Error(), 216 }, 217 "invalid input": { 218 generate: func(t *testing.T) UnsignedAtomicTx { 219 tx := *importTx 220 tx.ImportedInputs = []*avax.TransferableInput{ 221 tx.ImportedInputs[0], 222 nil, 223 } 224 return &tx 225 }, 226 ctx: ctx, 227 rules: apricotRulesPhase0, 228 expectedErr: "atomic input failed verification", 229 }, 230 "unsorted outputs phase 0 passes verification": { 231 generate: func(t *testing.T) UnsignedAtomicTx { 232 tx := *importTx 233 tx.Outs = []EVMOutput{ 234 tx.Outs[1], 235 tx.Outs[0], 236 } 237 return &tx 238 }, 239 ctx: ctx, 240 rules: apricotRulesPhase0, 241 expectedErr: "", 242 }, 243 "non-unique outputs phase 0 passes verification": { 244 generate: func(t *testing.T) UnsignedAtomicTx { 245 tx := *importTx 246 tx.Outs = []EVMOutput{ 247 tx.Outs[0], 248 tx.Outs[0], 249 } 250 return &tx 251 }, 252 ctx: ctx, 253 rules: apricotRulesPhase0, 254 expectedErr: "", 255 }, 256 "unsorted outputs phase 1 fails verification": { 257 generate: func(t *testing.T) UnsignedAtomicTx { 258 tx := *importTx 259 tx.Outs = []EVMOutput{ 260 tx.Outs[1], 261 tx.Outs[0], 262 } 263 return &tx 264 }, 265 ctx: ctx, 266 rules: apricotRulesPhase1, 267 expectedErr: errOutputsNotSorted.Error(), 268 }, 269 "non-unique outputs phase 1 passes verification": { 270 generate: func(t *testing.T) UnsignedAtomicTx { 271 tx := *importTx 272 tx.Outs = []EVMOutput{ 273 tx.Outs[0], 274 tx.Outs[0], 275 } 276 return &tx 277 }, 278 ctx: ctx, 279 rules: apricotRulesPhase1, 280 expectedErr: "", 281 }, 282 "outputs not sorted and unique phase 2 fails verification": { 283 generate: func(t *testing.T) UnsignedAtomicTx { 284 tx := *importTx 285 tx.Outs = []EVMOutput{ 286 tx.Outs[0], 287 tx.Outs[0], 288 } 289 return &tx 290 }, 291 ctx: ctx, 292 rules: apricotRulesPhase2, 293 expectedErr: errOutputsNotSortedUnique.Error(), 294 }, 295 "outputs not sorted phase 2 fails verification": { 296 generate: func(t *testing.T) UnsignedAtomicTx { 297 tx := *importTx 298 tx.Outs = []EVMOutput{ 299 tx.Outs[1], 300 tx.Outs[0], 301 } 302 return &tx 303 }, 304 ctx: ctx, 305 rules: apricotRulesPhase2, 306 expectedErr: errOutputsNotSortedUnique.Error(), 307 }, 308 "invalid EVMOutput fails verification": { 309 generate: func(t *testing.T) UnsignedAtomicTx { 310 tx := *importTx 311 tx.Outs = []EVMOutput{ 312 { 313 Address: testEthAddrs[0], 314 Amount: 0, 315 AssetID: testAvaxAssetID, 316 }, 317 } 318 return &tx 319 }, 320 ctx: ctx, 321 rules: apricotRulesPhase0, 322 expectedErr: "EVM Output failed verification", 323 }, 324 "no outputs apricot phase 3": { 325 generate: func(t *testing.T) UnsignedAtomicTx { 326 tx := *importTx 327 tx.Outs = nil 328 return &tx 329 }, 330 ctx: ctx, 331 rules: apricotRulesPhase3, 332 expectedErr: errNoEVMOutputs.Error(), 333 }, 334 "non-AVAX input Apricot Phase 6": { 335 generate: func(t *testing.T) UnsignedAtomicTx { 336 tx := *importTx 337 tx.ImportedInputs = []*avax.TransferableInput{ 338 { 339 UTXOID: avax.UTXOID{ 340 TxID: txID, 341 OutputIndex: uint32(0), 342 }, 343 Asset: avax.Asset{ID: ids.GenerateTestID()}, 344 In: &secp256k1fx.TransferInput{ 345 Amt: importAmount, 346 Input: secp256k1fx.Input{ 347 SigIndices: []uint32{0}, 348 }, 349 }, 350 }, 351 } 352 return &tx 353 }, 354 ctx: ctx, 355 rules: apricotRulesPhase6, 356 expectedErr: "", 357 }, 358 "non-AVAX output Apricot Phase 6": { 359 generate: func(t *testing.T) UnsignedAtomicTx { 360 tx := *importTx 361 tx.Outs = []EVMOutput{ 362 { 363 Address: importTx.Outs[0].Address, 364 Amount: importTx.Outs[0].Amount, 365 AssetID: ids.GenerateTestID(), 366 }, 367 } 368 return &tx 369 }, 370 ctx: ctx, 371 rules: apricotRulesPhase6, 372 expectedErr: "", 373 }, 374 "non-AVAX input Banff": { 375 generate: func(t *testing.T) UnsignedAtomicTx { 376 tx := *importTx 377 tx.ImportedInputs = []*avax.TransferableInput{ 378 { 379 UTXOID: avax.UTXOID{ 380 TxID: txID, 381 OutputIndex: uint32(0), 382 }, 383 Asset: avax.Asset{ID: ids.GenerateTestID()}, 384 In: &secp256k1fx.TransferInput{ 385 Amt: importAmount, 386 Input: secp256k1fx.Input{ 387 SigIndices: []uint32{0}, 388 }, 389 }, 390 }, 391 } 392 return &tx 393 }, 394 ctx: ctx, 395 rules: banffRules, 396 expectedErr: errImportNonAVAXInputBanff.Error(), 397 }, 398 "non-AVAX output Banff": { 399 generate: func(t *testing.T) UnsignedAtomicTx { 400 tx := *importTx 401 tx.Outs = []EVMOutput{ 402 { 403 Address: importTx.Outs[0].Address, 404 Amount: importTx.Outs[0].Amount, 405 AssetID: ids.GenerateTestID(), 406 }, 407 } 408 return &tx 409 }, 410 ctx: ctx, 411 rules: banffRules, 412 expectedErr: errImportNonAVAXOutputBanff.Error(), 413 }, 414 } 415 for name, test := range tests { 416 t.Run(name, func(t *testing.T) { 417 executeTxVerifyTest(t, test) 418 }) 419 } 420 } 421 422 func TestNewImportTx(t *testing.T) { 423 importAmount := uint64(5000000) 424 // createNewImportAVAXTx adds a UTXO to shared memory and then constructs a new import transaction 425 // and checks that it has the correct fee for the base fee that has been used 426 createNewImportAVAXTx := func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 427 txID := ids.GenerateTestID() 428 _, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, importAmount, testShortIDAddrs[0]) 429 if err != nil { 430 t.Fatal(err) 431 } 432 433 tx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]}) 434 if err != nil { 435 t.Fatal(err) 436 } 437 importTx := tx.UnsignedAtomicTx 438 var actualFee uint64 439 actualAVAXBurned, err := importTx.Burned(vm.ctx.AVAXAssetID) 440 if err != nil { 441 t.Fatal(err) 442 } 443 rules := vm.currentRules() 444 switch { 445 case rules.IsApricotPhase3: 446 actualCost, err := importTx.GasUsed(rules.IsApricotPhase5) 447 if err != nil { 448 t.Fatal(err) 449 } 450 actualFee, err = calculateDynamicFee(actualCost, initialBaseFee) 451 if err != nil { 452 t.Fatal(err) 453 } 454 case rules.IsApricotPhase2: 455 actualFee = 1000000 456 default: 457 actualFee = 0 458 } 459 460 if actualAVAXBurned != actualFee { 461 t.Fatalf("AVAX burned (%d) != actual fee (%d)", actualAVAXBurned, actualFee) 462 } 463 464 return tx 465 } 466 checkState := func(t *testing.T, vm *VM) { 467 txs := vm.LastAcceptedBlockInternal().(*Block).atomicTxs 468 if len(txs) != 1 { 469 t.Fatalf("Expected one import tx to be in the last accepted block, but found %d", len(txs)) 470 } 471 472 tx := txs[0] 473 actualAVAXBurned, err := tx.UnsignedAtomicTx.Burned(vm.ctx.AVAXAssetID) 474 if err != nil { 475 t.Fatal(err) 476 } 477 478 // Ensure that the UTXO has been removed from shared memory within Accept 479 addrSet := ids.ShortSet{} 480 addrSet.Add(testShortIDAddrs[0]) 481 utxos, _, _, err := vm.GetAtomicUTXOs(vm.ctx.XChainID, addrSet, ids.ShortEmpty, ids.Empty, -1) 482 if err != nil { 483 t.Fatal(err) 484 } 485 if len(utxos) != 0 { 486 t.Fatalf("Expected to find 0 UTXOs after accepting import transaction, but found %d", len(utxos)) 487 } 488 489 // Ensure that the call to EVMStateTransfer correctly updates the balance of [addr] 490 sdb, err := vm.blockChain.State() 491 if err != nil { 492 t.Fatal(err) 493 } 494 495 expectedRemainingBalance := new(big.Int).Mul(new(big.Int).SetUint64(importAmount-actualAVAXBurned), x2cRate) 496 addr := GetEthAddress(testKeys[0]) 497 if actualBalance := sdb.GetBalance(addr); actualBalance.Cmp(expectedRemainingBalance) != 0 { 498 t.Fatalf("address remaining balance %s equal %s not %s", addr.String(), actualBalance, expectedRemainingBalance) 499 } 500 } 501 tests2 := map[string]atomicTxTest{ 502 "apricot phase 0": { 503 setup: createNewImportAVAXTx, 504 checkState: checkState, 505 genesisJSON: genesisJSONApricotPhase0, 506 }, 507 "apricot phase 1": { 508 setup: createNewImportAVAXTx, 509 checkState: checkState, 510 genesisJSON: genesisJSONApricotPhase1, 511 }, 512 "apricot phase 2": { 513 setup: createNewImportAVAXTx, 514 checkState: checkState, 515 genesisJSON: genesisJSONApricotPhase2, 516 }, 517 "apricot phase 3": { 518 setup: createNewImportAVAXTx, 519 checkState: checkState, 520 genesisJSON: genesisJSONApricotPhase3, 521 }, 522 } 523 524 for name, test := range tests2 { 525 t.Run(name, func(t *testing.T) { 526 executeTxTest(t, test) 527 }) 528 } 529 } 530 531 // Note: this is a brittle test to ensure that the gas cost of a transaction does 532 // not change 533 func TestImportTxGasCost(t *testing.T) { 534 avaxAssetID := ids.GenerateTestID() 535 antAssetID := ids.GenerateTestID() 536 chainID := ids.GenerateTestID() 537 xChainID := ids.GenerateTestID() 538 networkID := uint32(5) 539 importAmount := uint64(5000000) 540 541 tests := map[string]struct { 542 UnsignedImportTx *UnsignedImportTx 543 Keys [][]*crypto.PrivateKeySECP256K1R 544 545 ExpectedGasUsed uint64 546 ExpectedFee uint64 547 BaseFee *big.Int 548 FixedFee bool 549 }{ 550 "simple import": { 551 UnsignedImportTx: &UnsignedImportTx{ 552 NetworkID: networkID, 553 BlockchainID: chainID, 554 SourceChain: xChainID, 555 ImportedInputs: []*avax.TransferableInput{{ 556 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 557 Asset: avax.Asset{ID: avaxAssetID}, 558 In: &secp256k1fx.TransferInput{ 559 Amt: importAmount, 560 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 561 }, 562 }}, 563 Outs: []EVMOutput{{ 564 Address: testEthAddrs[0], 565 Amount: importAmount, 566 AssetID: avaxAssetID, 567 }}, 568 }, 569 Keys: [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}, 570 ExpectedGasUsed: 1230, 571 ExpectedFee: 30750, 572 BaseFee: big.NewInt(25 * params.GWei), 573 }, 574 "simple import 1wei": { 575 UnsignedImportTx: &UnsignedImportTx{ 576 NetworkID: networkID, 577 BlockchainID: chainID, 578 SourceChain: xChainID, 579 ImportedInputs: []*avax.TransferableInput{{ 580 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 581 Asset: avax.Asset{ID: avaxAssetID}, 582 In: &secp256k1fx.TransferInput{ 583 Amt: importAmount, 584 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 585 }, 586 }}, 587 Outs: []EVMOutput{{ 588 Address: testEthAddrs[0], 589 Amount: importAmount, 590 AssetID: avaxAssetID, 591 }}, 592 }, 593 Keys: [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}, 594 ExpectedGasUsed: 1230, 595 ExpectedFee: 1, 596 BaseFee: big.NewInt(1), 597 }, 598 "simple import 1wei + fixed fee": { 599 UnsignedImportTx: &UnsignedImportTx{ 600 NetworkID: networkID, 601 BlockchainID: chainID, 602 SourceChain: xChainID, 603 ImportedInputs: []*avax.TransferableInput{{ 604 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 605 Asset: avax.Asset{ID: avaxAssetID}, 606 In: &secp256k1fx.TransferInput{ 607 Amt: importAmount, 608 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 609 }, 610 }}, 611 Outs: []EVMOutput{{ 612 Address: testEthAddrs[0], 613 Amount: importAmount, 614 AssetID: avaxAssetID, 615 }}, 616 }, 617 Keys: [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}, 618 ExpectedGasUsed: 11230, 619 ExpectedFee: 1, 620 BaseFee: big.NewInt(1), 621 FixedFee: true, 622 }, 623 "simple ANT import": { 624 UnsignedImportTx: &UnsignedImportTx{ 625 NetworkID: networkID, 626 BlockchainID: chainID, 627 SourceChain: xChainID, 628 ImportedInputs: []*avax.TransferableInput{ 629 { 630 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 631 Asset: avax.Asset{ID: avaxAssetID}, 632 In: &secp256k1fx.TransferInput{ 633 Amt: importAmount, 634 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 635 }, 636 }, 637 { 638 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 639 Asset: avax.Asset{ID: antAssetID}, 640 In: &secp256k1fx.TransferInput{ 641 Amt: importAmount, 642 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 643 }, 644 }, 645 }, 646 Outs: []EVMOutput{ 647 { 648 Address: testEthAddrs[0], 649 Amount: importAmount, 650 AssetID: antAssetID, 651 }, 652 }, 653 }, 654 Keys: [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}, {testKeys[0]}}, 655 ExpectedGasUsed: 2318, 656 ExpectedFee: 57950, 657 BaseFee: big.NewInt(25 * params.GWei), 658 }, 659 "complex ANT import": { 660 UnsignedImportTx: &UnsignedImportTx{ 661 NetworkID: networkID, 662 BlockchainID: chainID, 663 SourceChain: xChainID, 664 ImportedInputs: []*avax.TransferableInput{ 665 { 666 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 667 Asset: avax.Asset{ID: avaxAssetID}, 668 In: &secp256k1fx.TransferInput{ 669 Amt: importAmount, 670 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 671 }, 672 }, 673 { 674 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 675 Asset: avax.Asset{ID: antAssetID}, 676 In: &secp256k1fx.TransferInput{ 677 Amt: importAmount, 678 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 679 }, 680 }, 681 }, 682 Outs: []EVMOutput{ 683 { 684 Address: testEthAddrs[0], 685 Amount: importAmount, 686 AssetID: avaxAssetID, 687 }, 688 { 689 Address: testEthAddrs[0], 690 Amount: importAmount, 691 AssetID: antAssetID, 692 }, 693 }, 694 }, 695 Keys: [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}, {testKeys[0]}}, 696 ExpectedGasUsed: 2378, 697 ExpectedFee: 59450, 698 BaseFee: big.NewInt(25 * params.GWei), 699 }, 700 "multisig import": { 701 UnsignedImportTx: &UnsignedImportTx{ 702 NetworkID: networkID, 703 BlockchainID: chainID, 704 SourceChain: xChainID, 705 ImportedInputs: []*avax.TransferableInput{{ 706 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 707 Asset: avax.Asset{ID: avaxAssetID}, 708 In: &secp256k1fx.TransferInput{ 709 Amt: importAmount, 710 Input: secp256k1fx.Input{SigIndices: []uint32{0, 1}}, 711 }, 712 }}, 713 Outs: []EVMOutput{{ 714 Address: testEthAddrs[0], 715 Amount: importAmount, 716 AssetID: avaxAssetID, 717 }}, 718 }, 719 Keys: [][]*crypto.PrivateKeySECP256K1R{{testKeys[0], testKeys[1]}}, 720 ExpectedGasUsed: 2234, 721 ExpectedFee: 55850, 722 BaseFee: big.NewInt(25 * params.GWei), 723 }, 724 "large import": { 725 UnsignedImportTx: &UnsignedImportTx{ 726 NetworkID: networkID, 727 BlockchainID: chainID, 728 SourceChain: xChainID, 729 ImportedInputs: []*avax.TransferableInput{ 730 { 731 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 732 Asset: avax.Asset{ID: avaxAssetID}, 733 In: &secp256k1fx.TransferInput{ 734 Amt: importAmount, 735 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 736 }, 737 }, 738 { 739 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 740 Asset: avax.Asset{ID: avaxAssetID}, 741 In: &secp256k1fx.TransferInput{ 742 Amt: importAmount, 743 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 744 }, 745 }, 746 { 747 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 748 Asset: avax.Asset{ID: avaxAssetID}, 749 In: &secp256k1fx.TransferInput{ 750 Amt: importAmount, 751 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 752 }, 753 }, 754 { 755 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 756 Asset: avax.Asset{ID: avaxAssetID}, 757 In: &secp256k1fx.TransferInput{ 758 Amt: importAmount, 759 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 760 }, 761 }, 762 { 763 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 764 Asset: avax.Asset{ID: avaxAssetID}, 765 In: &secp256k1fx.TransferInput{ 766 Amt: importAmount, 767 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 768 }, 769 }, 770 { 771 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 772 Asset: avax.Asset{ID: avaxAssetID}, 773 In: &secp256k1fx.TransferInput{ 774 Amt: importAmount, 775 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 776 }, 777 }, 778 { 779 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 780 Asset: avax.Asset{ID: avaxAssetID}, 781 In: &secp256k1fx.TransferInput{ 782 Amt: importAmount, 783 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 784 }, 785 }, 786 { 787 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 788 Asset: avax.Asset{ID: avaxAssetID}, 789 In: &secp256k1fx.TransferInput{ 790 Amt: importAmount, 791 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 792 }, 793 }, 794 { 795 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 796 Asset: avax.Asset{ID: avaxAssetID}, 797 In: &secp256k1fx.TransferInput{ 798 Amt: importAmount, 799 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 800 }, 801 }, 802 { 803 UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()}, 804 Asset: avax.Asset{ID: avaxAssetID}, 805 In: &secp256k1fx.TransferInput{ 806 Amt: importAmount, 807 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 808 }, 809 }, 810 }, 811 Outs: []EVMOutput{ 812 { 813 Address: testEthAddrs[0], 814 Amount: importAmount * 10, 815 AssetID: avaxAssetID, 816 }, 817 }, 818 }, 819 Keys: [][]*crypto.PrivateKeySECP256K1R{ 820 {testKeys[0]}, 821 {testKeys[0]}, 822 {testKeys[0]}, 823 {testKeys[0]}, 824 {testKeys[0]}, 825 {testKeys[0]}, 826 {testKeys[0]}, 827 {testKeys[0]}, 828 {testKeys[0]}, 829 {testKeys[0]}, 830 }, 831 ExpectedGasUsed: 11022, 832 ExpectedFee: 275550, 833 BaseFee: big.NewInt(25 * params.GWei), 834 }, 835 } 836 837 for name, test := range tests { 838 t.Run(name, func(t *testing.T) { 839 tx := &Tx{UnsignedAtomicTx: test.UnsignedImportTx} 840 841 // Sign with the correct key 842 if err := tx.Sign(Codec, test.Keys); err != nil { 843 t.Fatal(err) 844 } 845 846 gasUsed, err := tx.GasUsed(test.FixedFee) 847 if err != nil { 848 t.Fatal(err) 849 } 850 if gasUsed != test.ExpectedGasUsed { 851 t.Fatalf("Expected gasUsed to be %d, but found %d", test.ExpectedGasUsed, gasUsed) 852 } 853 854 fee, err := calculateDynamicFee(gasUsed, test.BaseFee) 855 if err != nil { 856 t.Fatal(err) 857 } 858 if fee != test.ExpectedFee { 859 t.Fatalf("Expected fee to be %d, but found %d", test.ExpectedFee, fee) 860 } 861 }) 862 } 863 } 864 865 func TestImportTxSemanticVerify(t *testing.T) { 866 tests := map[string]atomicTxTest{ 867 "UTXO not present during bootstrapping": { 868 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 869 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 870 NetworkID: vm.ctx.NetworkID, 871 BlockchainID: vm.ctx.ChainID, 872 SourceChain: vm.ctx.XChainID, 873 ImportedInputs: []*avax.TransferableInput{{ 874 UTXOID: avax.UTXOID{ 875 TxID: ids.GenerateTestID(), 876 }, 877 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 878 In: &secp256k1fx.TransferInput{ 879 Amt: 1, 880 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 881 }, 882 }}, 883 Outs: []EVMOutput{{ 884 Address: testEthAddrs[0], 885 Amount: 1, 886 AssetID: vm.ctx.AVAXAssetID, 887 }}, 888 }} 889 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 890 t.Fatal(err) 891 } 892 return tx 893 }, 894 bootstrapping: true, 895 }, 896 "UTXO not present": { 897 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 898 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 899 NetworkID: vm.ctx.NetworkID, 900 BlockchainID: vm.ctx.ChainID, 901 SourceChain: vm.ctx.XChainID, 902 ImportedInputs: []*avax.TransferableInput{{ 903 UTXOID: avax.UTXOID{ 904 TxID: ids.GenerateTestID(), 905 }, 906 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 907 In: &secp256k1fx.TransferInput{ 908 Amt: 1, 909 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 910 }, 911 }}, 912 Outs: []EVMOutput{{ 913 Address: testEthAddrs[0], 914 Amount: 1, 915 AssetID: vm.ctx.AVAXAssetID, 916 }}, 917 }} 918 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 919 t.Fatal(err) 920 } 921 return tx 922 }, 923 semanticVerifyErr: "failed to fetch import UTXOs from", 924 }, 925 "garbage UTXO": { 926 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 927 utxoID := avax.UTXOID{TxID: ids.GenerateTestID()} 928 xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID) 929 inputID := utxoID.InputID() 930 if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{ 931 Key: inputID[:], 932 Value: []byte("hey there"), 933 Traits: [][]byte{ 934 testShortIDAddrs[0].Bytes(), 935 }, 936 }}}}); err != nil { 937 t.Fatal(err) 938 } 939 940 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 941 NetworkID: vm.ctx.NetworkID, 942 BlockchainID: vm.ctx.ChainID, 943 SourceChain: vm.ctx.XChainID, 944 ImportedInputs: []*avax.TransferableInput{{ 945 UTXOID: utxoID, 946 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 947 In: &secp256k1fx.TransferInput{ 948 Amt: 1, 949 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 950 }, 951 }}, 952 Outs: []EVMOutput{{ 953 Address: testEthAddrs[0], 954 Amount: 1, 955 AssetID: vm.ctx.AVAXAssetID, 956 }}, 957 }} 958 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 959 t.Fatal(err) 960 } 961 return tx 962 }, 963 semanticVerifyErr: "failed to unmarshal UTXO", 964 }, 965 "UTXO AssetID mismatch": { 966 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 967 txID := ids.GenerateTestID() 968 expectedAssetID := ids.GenerateTestID() 969 utxo, err := addUTXO(sharedMemory, vm.ctx, txID, 0, expectedAssetID, 1, testShortIDAddrs[0]) 970 if err != nil { 971 t.Fatal(err) 972 } 973 974 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 975 NetworkID: vm.ctx.NetworkID, 976 BlockchainID: vm.ctx.ChainID, 977 SourceChain: vm.ctx.XChainID, 978 ImportedInputs: []*avax.TransferableInput{{ 979 UTXOID: utxo.UTXOID, 980 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, // Use a different assetID then the actual UTXO 981 In: &secp256k1fx.TransferInput{ 982 Amt: 1, 983 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 984 }, 985 }}, 986 Outs: []EVMOutput{{ 987 Address: testEthAddrs[0], 988 Amount: 1, 989 AssetID: vm.ctx.AVAXAssetID, 990 }}, 991 }} 992 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 993 t.Fatal(err) 994 } 995 return tx 996 }, 997 semanticVerifyErr: errAssetIDMismatch.Error(), 998 }, 999 "insufficient AVAX funds": { 1000 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 1001 txID := ids.GenerateTestID() 1002 utxo, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, 1, testShortIDAddrs[0]) 1003 if err != nil { 1004 t.Fatal(err) 1005 } 1006 1007 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 1008 NetworkID: vm.ctx.NetworkID, 1009 BlockchainID: vm.ctx.ChainID, 1010 SourceChain: vm.ctx.XChainID, 1011 ImportedInputs: []*avax.TransferableInput{{ 1012 UTXOID: utxo.UTXOID, 1013 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 1014 In: &secp256k1fx.TransferInput{ 1015 Amt: 1, 1016 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 1017 }, 1018 }}, 1019 Outs: []EVMOutput{{ 1020 Address: testEthAddrs[0], 1021 Amount: 2, // Produce more output than is consumed by the transaction 1022 AssetID: vm.ctx.AVAXAssetID, 1023 }}, 1024 }} 1025 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 1026 t.Fatal(err) 1027 } 1028 return tx 1029 }, 1030 semanticVerifyErr: "import tx flow check failed due to", 1031 }, 1032 "insufficient non-AVAX funds": { 1033 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 1034 txID := ids.GenerateTestID() 1035 assetID := ids.GenerateTestID() 1036 utxo, err := addUTXO(sharedMemory, vm.ctx, txID, 0, assetID, 1, testShortIDAddrs[0]) 1037 if err != nil { 1038 t.Fatal(err) 1039 } 1040 1041 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 1042 NetworkID: vm.ctx.NetworkID, 1043 BlockchainID: vm.ctx.ChainID, 1044 SourceChain: vm.ctx.XChainID, 1045 ImportedInputs: []*avax.TransferableInput{{ 1046 UTXOID: utxo.UTXOID, 1047 Asset: avax.Asset{ID: assetID}, 1048 In: &secp256k1fx.TransferInput{ 1049 Amt: 1, 1050 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 1051 }, 1052 }}, 1053 Outs: []EVMOutput{{ 1054 Address: testEthAddrs[0], 1055 Amount: 2, // Produce more output than is consumed by the transaction 1056 AssetID: assetID, 1057 }}, 1058 }} 1059 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 1060 t.Fatal(err) 1061 } 1062 return tx 1063 }, 1064 semanticVerifyErr: "import tx flow check failed due to", 1065 }, 1066 "no signatures": { 1067 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 1068 txID := ids.GenerateTestID() 1069 utxo, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, 1, testShortIDAddrs[0]) 1070 if err != nil { 1071 t.Fatal(err) 1072 } 1073 1074 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 1075 NetworkID: vm.ctx.NetworkID, 1076 BlockchainID: vm.ctx.ChainID, 1077 SourceChain: vm.ctx.XChainID, 1078 ImportedInputs: []*avax.TransferableInput{{ 1079 UTXOID: utxo.UTXOID, 1080 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 1081 In: &secp256k1fx.TransferInput{ 1082 Amt: 1, 1083 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 1084 }, 1085 }}, 1086 Outs: []EVMOutput{{ 1087 Address: testEthAddrs[0], 1088 Amount: 1, 1089 AssetID: vm.ctx.AVAXAssetID, 1090 }}, 1091 }} 1092 if err := tx.Sign(vm.codec, nil); err != nil { 1093 t.Fatal(err) 1094 } 1095 return tx 1096 }, 1097 semanticVerifyErr: "import tx contained mismatched number of inputs/credentials", 1098 }, 1099 "incorrect signature": { 1100 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 1101 txID := ids.GenerateTestID() 1102 utxo, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, 1, testShortIDAddrs[0]) 1103 if err != nil { 1104 t.Fatal(err) 1105 } 1106 1107 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 1108 NetworkID: vm.ctx.NetworkID, 1109 BlockchainID: vm.ctx.ChainID, 1110 SourceChain: vm.ctx.XChainID, 1111 ImportedInputs: []*avax.TransferableInput{{ 1112 UTXOID: utxo.UTXOID, 1113 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 1114 In: &secp256k1fx.TransferInput{ 1115 Amt: 1, 1116 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 1117 }, 1118 }}, 1119 Outs: []EVMOutput{{ 1120 Address: testEthAddrs[0], 1121 Amount: 1, 1122 AssetID: vm.ctx.AVAXAssetID, 1123 }}, 1124 }} 1125 // Sign the transaction with the incorrect key 1126 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[1]}}); err != nil { 1127 t.Fatal(err) 1128 } 1129 return tx 1130 }, 1131 semanticVerifyErr: "import tx transfer failed verification", 1132 }, 1133 "non-unique EVM Outputs": { 1134 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 1135 txID := ids.GenerateTestID() 1136 utxo, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, 2, testShortIDAddrs[0]) 1137 if err != nil { 1138 t.Fatal(err) 1139 } 1140 1141 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 1142 NetworkID: vm.ctx.NetworkID, 1143 BlockchainID: vm.ctx.ChainID, 1144 SourceChain: vm.ctx.XChainID, 1145 ImportedInputs: []*avax.TransferableInput{{ 1146 UTXOID: utxo.UTXOID, 1147 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 1148 In: &secp256k1fx.TransferInput{ 1149 Amt: 2, 1150 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 1151 }, 1152 }}, 1153 Outs: []EVMOutput{ 1154 { 1155 Address: testEthAddrs[0], 1156 Amount: 1, 1157 AssetID: vm.ctx.AVAXAssetID, 1158 }, 1159 { 1160 Address: testEthAddrs[0], 1161 Amount: 1, 1162 AssetID: vm.ctx.AVAXAssetID, 1163 }, 1164 }, 1165 }} 1166 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 1167 t.Fatal(err) 1168 } 1169 return tx 1170 }, 1171 genesisJSON: genesisJSONApricotPhase3, 1172 semanticVerifyErr: errOutputsNotSortedUnique.Error(), 1173 }, 1174 } 1175 1176 for name, test := range tests { 1177 t.Run(name, func(t *testing.T) { 1178 executeTxTest(t, test) 1179 }) 1180 } 1181 } 1182 1183 func TestImportTxEVMStateTransfer(t *testing.T) { 1184 assetID := ids.GenerateTestID() 1185 tests := map[string]atomicTxTest{ 1186 "AVAX UTXO": { 1187 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 1188 txID := ids.GenerateTestID() 1189 utxo, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, 1, testShortIDAddrs[0]) 1190 if err != nil { 1191 t.Fatal(err) 1192 } 1193 1194 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 1195 NetworkID: vm.ctx.NetworkID, 1196 BlockchainID: vm.ctx.ChainID, 1197 SourceChain: vm.ctx.XChainID, 1198 ImportedInputs: []*avax.TransferableInput{{ 1199 UTXOID: utxo.UTXOID, 1200 Asset: avax.Asset{ID: vm.ctx.AVAXAssetID}, 1201 In: &secp256k1fx.TransferInput{ 1202 Amt: 1, 1203 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 1204 }, 1205 }}, 1206 Outs: []EVMOutput{{ 1207 Address: testEthAddrs[0], 1208 Amount: 1, 1209 AssetID: vm.ctx.AVAXAssetID, 1210 }}, 1211 }} 1212 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 1213 t.Fatal(err) 1214 } 1215 return tx 1216 }, 1217 checkState: func(t *testing.T, vm *VM) { 1218 lastAcceptedBlock := vm.LastAcceptedBlockInternal().(*Block) 1219 1220 sdb, err := vm.blockChain.StateAt(lastAcceptedBlock.ethBlock.Root()) 1221 if err != nil { 1222 t.Fatal(err) 1223 } 1224 1225 avaxBalance := sdb.GetBalance(testEthAddrs[0]) 1226 if avaxBalance.Cmp(x2cRate) != 0 { 1227 t.Fatalf("Expected AVAX balance to be %d, found balance: %d", x2cRate, avaxBalance) 1228 } 1229 }, 1230 }, 1231 "non-AVAX UTXO": { 1232 setup: func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) *Tx { 1233 txID := ids.GenerateTestID() 1234 utxo, err := addUTXO(sharedMemory, vm.ctx, txID, 0, assetID, 1, testShortIDAddrs[0]) 1235 if err != nil { 1236 t.Fatal(err) 1237 } 1238 1239 tx := &Tx{UnsignedAtomicTx: &UnsignedImportTx{ 1240 NetworkID: vm.ctx.NetworkID, 1241 BlockchainID: vm.ctx.ChainID, 1242 SourceChain: vm.ctx.XChainID, 1243 ImportedInputs: []*avax.TransferableInput{{ 1244 UTXOID: utxo.UTXOID, 1245 Asset: avax.Asset{ID: assetID}, 1246 In: &secp256k1fx.TransferInput{ 1247 Amt: 1, 1248 Input: secp256k1fx.Input{SigIndices: []uint32{0}}, 1249 }, 1250 }}, 1251 Outs: []EVMOutput{{ 1252 Address: testEthAddrs[0], 1253 Amount: 1, 1254 AssetID: assetID, 1255 }}, 1256 }} 1257 if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil { 1258 t.Fatal(err) 1259 } 1260 return tx 1261 }, 1262 checkState: func(t *testing.T, vm *VM) { 1263 lastAcceptedBlock := vm.LastAcceptedBlockInternal().(*Block) 1264 1265 sdb, err := vm.blockChain.StateAt(lastAcceptedBlock.ethBlock.Root()) 1266 if err != nil { 1267 t.Fatal(err) 1268 } 1269 1270 assetBalance := sdb.GetBalanceMultiCoin(testEthAddrs[0], common.Hash(assetID)) 1271 if assetBalance.Cmp(common.Big1) != 0 { 1272 t.Fatalf("Expected asset balance to be %d, found balance: %d", common.Big1, assetBalance) 1273 } 1274 avaxBalance := sdb.GetBalance(testEthAddrs[0]) 1275 if avaxBalance.Cmp(common.Big0) != 0 { 1276 t.Fatalf("Expected AVAX balance to be 0, found balance: %d", avaxBalance) 1277 } 1278 }, 1279 }, 1280 } 1281 1282 for name, test := range tests { 1283 t.Run(name, func(t *testing.T) { 1284 executeTxTest(t, test) 1285 }) 1286 } 1287 }