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  }