gitlab.com/flarenetwork/coreth@v0.1.1/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  	"gitlab.com/flarenetwork/coreth/params"
    11  
    12  	"github.com/ava-labs/avalanchego/chains/atomic"
    13  	"github.com/ava-labs/avalanchego/ids"
    14  	"github.com/ava-labs/avalanchego/utils/crypto"
    15  	"github.com/ava-labs/avalanchego/utils/units"
    16  	"github.com/ava-labs/avalanchego/vms/components/avax"
    17  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    18  )
    19  
    20  func TestImportTxVerifyNil(t *testing.T) {
    21  	var importTx *UnsignedImportTx
    22  	if err := importTx.Verify(testXChainID, NewContext(), apricotRulesPhase1); err == nil {
    23  		t.Fatal("Verify should have failed due to nil transaction")
    24  	}
    25  }
    26  
    27  func TestImportTxVerify(t *testing.T) {
    28  	var importAmount uint64 = 10000000
    29  	txID := ids.ID{0xff}
    30  	importTx := &UnsignedImportTx{
    31  		NetworkID:    testNetworkID,
    32  		BlockchainID: testCChainID,
    33  		SourceChain:  testXChainID,
    34  		ImportedInputs: []*avax.TransferableInput{
    35  			{
    36  				UTXOID: avax.UTXOID{
    37  					TxID:        txID,
    38  					OutputIndex: uint32(0),
    39  				},
    40  				Asset: avax.Asset{ID: testAvaxAssetID},
    41  				In: &secp256k1fx.TransferInput{
    42  					Amt: importAmount,
    43  					Input: secp256k1fx.Input{
    44  						SigIndices: []uint32{0},
    45  					},
    46  				},
    47  			},
    48  			{
    49  				UTXOID: avax.UTXOID{
    50  					TxID:        txID,
    51  					OutputIndex: uint32(1),
    52  				},
    53  				Asset: avax.Asset{ID: testAvaxAssetID},
    54  				In: &secp256k1fx.TransferInput{
    55  					Amt: importAmount,
    56  					Input: secp256k1fx.Input{
    57  						SigIndices: []uint32{0},
    58  					},
    59  				},
    60  			},
    61  		},
    62  		Outs: []EVMOutput{
    63  			{
    64  				Address: testEthAddrs[0],
    65  				Amount:  importAmount - params.AvalancheAtomicTxFee,
    66  				AssetID: testAvaxAssetID,
    67  			},
    68  			{
    69  				Address: testEthAddrs[1],
    70  				Amount:  importAmount,
    71  				AssetID: testAvaxAssetID,
    72  			},
    73  		},
    74  	}
    75  
    76  	ctx := NewContext()
    77  
    78  	// // Sort the inputs and outputs to ensure the transaction is canonical
    79  	avax.SortTransferableInputs(importTx.ImportedInputs)
    80  	SortEVMOutputs(importTx.Outs)
    81  
    82  	// Test Valid ImportTx
    83  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err != nil {
    84  		t.Fatalf("Failed to verify ImportTx: %s", err)
    85  	}
    86  
    87  	importTx.NetworkID = testNetworkID + 1
    88  
    89  	// // Test Incorrect Network ID Errors
    90  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err == nil {
    91  		t.Fatal("ImportTx should have failed verification due to incorrect network ID")
    92  	}
    93  
    94  	importTx.NetworkID = testNetworkID
    95  	importTx.BlockchainID = nonExistentID
    96  	// // Test Incorrect Blockchain ID Errors
    97  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err == nil {
    98  		t.Fatal("ImportTx should have failed verification due to incorrect blockchain ID")
    99  	}
   100  
   101  	importTx.BlockchainID = testCChainID
   102  	importTx.SourceChain = nonExistentID
   103  	// // Test Incorrect Destination Chain ID Errors
   104  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err == nil {
   105  		t.Fatal("ImportTx should have failed verification due to incorrect source chain")
   106  	}
   107  
   108  	importTx.SourceChain = testXChainID
   109  	importedIns := importTx.ImportedInputs
   110  	evmOutputs := importTx.Outs
   111  	importTx.ImportedInputs = nil
   112  	// // Test No Imported Inputs Errors
   113  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err == nil {
   114  		t.Fatal("ImportTx should have failed verification due to no imported inputs")
   115  	}
   116  
   117  	importTx.ImportedInputs = []*avax.TransferableInput{importedIns[1], importedIns[0]}
   118  	// // Test Unsorted Imported Inputs Errors
   119  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err == nil {
   120  		t.Fatal("ImportTx should have failed verification due to unsorted import inputs")
   121  	}
   122  
   123  	importTx.ImportedInputs = []*avax.TransferableInput{importedIns[0], nil}
   124  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err == nil {
   125  		t.Fatal("ImportTx should have failed verification due to invalid input")
   126  	}
   127  
   128  	importTx.ImportedInputs = []*avax.TransferableInput{importedIns[0], importedIns[1]}
   129  	importTx.Outs = []EVMOutput{evmOutputs[1], evmOutputs[0]}
   130  	// Test unsorted EVM Outputs pass verification prior to AP1
   131  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase0); err != nil {
   132  		t.Fatalf("ImportTx should have passed verification prior to AP1, but failed due to %s", err)
   133  	}
   134  	// Test unsorted EVM Outputs fails verification after AP1
   135  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err == nil {
   136  		t.Fatal("ImportTx should have failed verification due to unsorted EVM Outputs in AP1")
   137  	}
   138  	importTx.Outs = []EVMOutput{
   139  		{
   140  			Address: testEthAddrs[0],
   141  			Amount:  0,
   142  			AssetID: testAvaxAssetID,
   143  		},
   144  	}
   145  	// Test ImportTx with invalid EVM Output Amount 0 fails verification
   146  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err == nil {
   147  		t.Fatal("ImportTx should have failed verification due to 0 value amount")
   148  	}
   149  	importTx.Outs = []EVMOutput{evmOutputs[0], evmOutputs[0]}
   150  	// Test non-unique EVM Outputs passes verification for AP0 and AP1
   151  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase0); err != nil {
   152  		t.Fatal(err)
   153  	}
   154  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase1); err != nil {
   155  		t.Fatal(err)
   156  	}
   157  	// Test non-unique EVM Outputs fails verification for AP2
   158  	if err := importTx.Verify(testXChainID, ctx, apricotRulesPhase2); err == nil {
   159  		t.Fatal("ImportTx should have failed verification due to non-unique outputs in AP2")
   160  	}
   161  }
   162  
   163  func TestImportTxSemanticVerifyApricotPhase0(t *testing.T) {
   164  	_, vm, _, sharedMemory := GenesisVM(t, false, genesisJSONApricotPhase0, "", "")
   165  
   166  	defer func() {
   167  		if err := vm.Shutdown(); err != nil {
   168  			t.Fatal(err)
   169  		}
   170  	}()
   171  
   172  	parent := vm.LastAcceptedBlockInternal().(*Block)
   173  	xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
   174  
   175  	importAmount := uint64(5000000)
   176  	utxoID := avax.UTXOID{
   177  		TxID: ids.ID{
   178  			0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   179  			0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   180  			0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   181  			0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   182  		},
   183  	}
   184  
   185  	utxo := &avax.UTXO{
   186  		UTXOID: utxoID,
   187  		Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
   188  		Out: &secp256k1fx.TransferOutput{
   189  			Amt: importAmount,
   190  			OutputOwners: secp256k1fx.OutputOwners{
   191  				Threshold: 1,
   192  				Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
   193  			},
   194  		},
   195  	}
   196  	utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  
   201  	evmOutput := EVMOutput{
   202  		Address: testEthAddrs[0],
   203  		Amount:  importAmount,
   204  		AssetID: vm.ctx.AVAXAssetID,
   205  	}
   206  	unsignedImportTx := &UnsignedImportTx{
   207  		NetworkID:    vm.ctx.NetworkID,
   208  		BlockchainID: vm.ctx.ChainID,
   209  		SourceChain:  vm.ctx.XChainID,
   210  		ImportedInputs: []*avax.TransferableInput{{
   211  			UTXOID: utxoID,
   212  			Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
   213  			In: &secp256k1fx.TransferInput{
   214  				Amt:   importAmount,
   215  				Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   216  			},
   217  		}},
   218  		Outs: []EVMOutput{evmOutput},
   219  	}
   220  
   221  	state, err := vm.chain.CurrentState()
   222  	if err != nil {
   223  		t.Fatalf("Failed to get last accepted stateDB due to: %s", err)
   224  	}
   225  
   226  	if empty := state.Empty(testEthAddrs[0]); !empty {
   227  		t.Fatal("Expected ethereum address to have empty starting balance.")
   228  	}
   229  
   230  	if err := unsignedImportTx.Verify(vm.ctx.XChainID, vm.ctx, apricotRulesPhase0); err != nil {
   231  		t.Fatal(err)
   232  	}
   233  
   234  	tx := &Tx{UnsignedAtomicTx: unsignedImportTx}
   235  
   236  	// Sign with the correct key
   237  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   238  		t.Fatal(err)
   239  	}
   240  
   241  	// Check that SemanticVerify passes without the UTXO being present during bootstrapping
   242  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase0); err != nil {
   243  		t.Fatal(err)
   244  	}
   245  	inputID := utxo.InputID()
   246  	if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{
   247  		Key:   inputID[:],
   248  		Value: utxoBytes,
   249  		Traits: [][]byte{
   250  			testKeys[0].PublicKey().Address().Bytes(),
   251  		},
   252  	}}}}); err != nil {
   253  		t.Fatal(err)
   254  	}
   255  
   256  	// Check that SemanticVerify passes when the UTXO is present during bootstrapping
   257  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase0); err != nil {
   258  		t.Fatal(err)
   259  	}
   260  
   261  	// Check that SemanticVerify does not pass if an additional output is added in
   262  	unsignedImportTx.Outs = append(unsignedImportTx.Outs, EVMOutput{
   263  		Address: testEthAddrs[1],
   264  		Amount:  importAmount,
   265  		AssetID: vm.ctx.AVAXAssetID,
   266  	})
   267  	// Sign the updated transaction
   268  	tx.Creds = nil
   269  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   270  		t.Fatal(err)
   271  	}
   272  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase0); err == nil {
   273  		t.Fatal("Semantic verification should have failed due to insufficient funds")
   274  	}
   275  
   276  	unsignedImportTx.Outs = []EVMOutput{evmOutput}
   277  	// Sign the updated transaction
   278  	tx.Creds = nil
   279  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   280  		t.Fatal(err)
   281  	}
   282  
   283  	if err := vm.Bootstrapping(); err != nil {
   284  		t.Fatal(err)
   285  	}
   286  
   287  	if err := vm.Bootstrapped(); err != nil {
   288  		t.Fatal(err)
   289  	}
   290  
   291  	vm.ctx.Bootstrapped()
   292  
   293  	// Remove the signature
   294  	tx.Creds = nil
   295  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase0); err == nil {
   296  		t.Fatal("SemanticVerify should have failed due to no signatures")
   297  	}
   298  
   299  	// Sign with the incorrect key
   300  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[1]}}); err != nil {
   301  		t.Fatal(err)
   302  	}
   303  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase0); err == nil {
   304  		t.Fatal("SemanticVerify should have failed due to an invalid signature")
   305  	}
   306  
   307  	// Re-sign with the correct key
   308  	tx.Creds = nil
   309  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   310  		t.Fatal(err)
   311  	}
   312  
   313  	// Check that SemanticVerify passes when the UTXO is present after bootstrapping
   314  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase0); err != nil {
   315  		t.Fatal(err)
   316  	}
   317  
   318  	commitBatch, err := vm.db.CommitBatch()
   319  	if err != nil {
   320  		t.Fatalf("Failed to create commit batch for VM due to %s", err)
   321  	}
   322  	if err := unsignedImportTx.Accept(vm.ctx, commitBatch); err != nil {
   323  		t.Fatalf("Accept failed due to: %s", err)
   324  	}
   325  
   326  	if err := unsignedImportTx.EVMStateTransfer(vm.ctx, state); err != nil {
   327  		t.Fatalf("EVM State Transfer failed due to: %s", err)
   328  	}
   329  
   330  	balance := state.GetBalance(testEthAddrs[0])
   331  	if balance == nil {
   332  		t.Fatal("Found nil balance for address receiving imported funds")
   333  	} else if balance.Uint64() != importAmount*x2cRate.Uint64() {
   334  		t.Fatalf("Balance was %d, but expected balance of: %d", balance.Uint64(), importAmount*x2cRate.Uint64())
   335  	}
   336  
   337  	// Check that SemanticVerify fails when the UTXO is not present after bootstrapping
   338  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase0); err == nil {
   339  		t.Fatal("Semantic verification should have failed after the UTXO removed from shared memory")
   340  	}
   341  }
   342  
   343  func TestImportTxSemanticVerifyApricotPhase2(t *testing.T) {
   344  	_, vm, _, sharedMemory := GenesisVM(t, false, genesisJSONApricotPhase2, "", "")
   345  
   346  	defer func() {
   347  		if err := vm.Shutdown(); err != nil {
   348  			t.Fatal(err)
   349  		}
   350  	}()
   351  
   352  	parent := vm.LastAcceptedBlockInternal().(*Block)
   353  	xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
   354  
   355  	importAmount := uint64(5000000)
   356  	utxoID := avax.UTXOID{
   357  		TxID: ids.ID{
   358  			0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   359  			0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   360  			0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   361  			0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   362  		},
   363  	}
   364  
   365  	utxo := &avax.UTXO{
   366  		UTXOID: utxoID,
   367  		Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
   368  		Out: &secp256k1fx.TransferOutput{
   369  			Amt: importAmount,
   370  			OutputOwners: secp256k1fx.OutputOwners{
   371  				Threshold: 1,
   372  				Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
   373  			},
   374  		},
   375  	}
   376  	utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
   377  	if err != nil {
   378  		t.Fatal(err)
   379  	}
   380  
   381  	evmOutput := EVMOutput{
   382  		Address: testEthAddrs[0],
   383  		Amount:  importAmount - params.AvalancheAtomicTxFee,
   384  		AssetID: vm.ctx.AVAXAssetID,
   385  	}
   386  	unsignedImportTx := &UnsignedImportTx{
   387  		NetworkID:    vm.ctx.NetworkID,
   388  		BlockchainID: vm.ctx.ChainID,
   389  		SourceChain:  vm.ctx.XChainID,
   390  		ImportedInputs: []*avax.TransferableInput{{
   391  			UTXOID: utxoID,
   392  			Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
   393  			In: &secp256k1fx.TransferInput{
   394  				Amt:   importAmount,
   395  				Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   396  			},
   397  		}},
   398  		Outs: []EVMOutput{evmOutput},
   399  	}
   400  
   401  	state, err := vm.chain.CurrentState()
   402  	if err != nil {
   403  		t.Fatalf("Failed to get last accepted stateDB due to: %s", err)
   404  	}
   405  
   406  	if empty := state.Empty(testEthAddrs[0]); !empty {
   407  		t.Fatal("Expected ethereum address to have empty starting balance.")
   408  	}
   409  
   410  	if err := unsignedImportTx.Verify(vm.ctx.XChainID, vm.ctx, apricotRulesPhase2); err != nil {
   411  		t.Fatal(err)
   412  	}
   413  
   414  	tx := &Tx{UnsignedAtomicTx: unsignedImportTx}
   415  
   416  	// Sign with the correct key
   417  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   418  		t.Fatal(err)
   419  	}
   420  
   421  	// Check that SemanticVerify passes without the UTXO being present during bootstrapping
   422  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase2); err != nil {
   423  		t.Fatal(err)
   424  	}
   425  	inputID := utxo.InputID()
   426  	if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{
   427  		Key:   inputID[:],
   428  		Value: utxoBytes,
   429  		Traits: [][]byte{
   430  			testKeys[0].PublicKey().Address().Bytes(),
   431  		},
   432  	}}}}); err != nil {
   433  		t.Fatal(err)
   434  	}
   435  
   436  	// Check that SemanticVerify passes when the UTXO is present during bootstrapping
   437  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase2); err != nil {
   438  		t.Fatal(err)
   439  	}
   440  
   441  	// Check that SemanticVerify does not pass if an additional output is added in
   442  	unsignedImportTx.Outs = append(unsignedImportTx.Outs, EVMOutput{
   443  		Address: testEthAddrs[1],
   444  		Amount:  importAmount,
   445  		AssetID: vm.ctx.AVAXAssetID,
   446  	})
   447  	// Sign the updated transaction
   448  	tx.Creds = nil
   449  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   450  		t.Fatal(err)
   451  	}
   452  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase2); err == nil {
   453  		t.Fatal("Semantic verification should have failed due to insufficient funds")
   454  	}
   455  
   456  	// Check that SemanticVerify errors when the transaction fee is not paid
   457  	unsignedImportTx.Outs = []EVMOutput{
   458  		{
   459  			Address: testEthAddrs[0],
   460  			Amount:  importAmount,
   461  			AssetID: vm.ctx.AVAXAssetID,
   462  		},
   463  	}
   464  	tx.Creds = nil
   465  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   466  		t.Fatal(err)
   467  	}
   468  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase2); err == nil {
   469  		t.Fatal("Semantic verification should have failed due to not paying the transaction fee")
   470  	}
   471  
   472  	unsignedImportTx.Outs = []EVMOutput{evmOutput}
   473  	// Sign the updated transaction
   474  	tx.Creds = nil
   475  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   476  		t.Fatal(err)
   477  	}
   478  
   479  	if err := vm.Bootstrapping(); err != nil {
   480  		t.Fatal(err)
   481  	}
   482  
   483  	if err := vm.Bootstrapped(); err != nil {
   484  		t.Fatal(err)
   485  	}
   486  
   487  	vm.ctx.Bootstrapped()
   488  
   489  	// Remove the signature
   490  	tx.Creds = nil
   491  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase2); err == nil {
   492  		t.Fatal("SemanticVerify should have failed due to no signatures")
   493  	}
   494  
   495  	// Sign with the incorrect key
   496  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[1]}}); err != nil {
   497  		t.Fatal(err)
   498  	}
   499  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase2); err == nil {
   500  		t.Fatal("SemanticVerify should have failed due to an invalid signature")
   501  	}
   502  
   503  	// Re-sign with the correct key
   504  	tx.Creds = nil
   505  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}}); err != nil {
   506  		t.Fatal(err)
   507  	}
   508  
   509  	// Check that SemanticVerify passes when the UTXO is present after bootstrapping
   510  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase2); err != nil {
   511  		t.Fatal(err)
   512  	}
   513  
   514  	commitBatch, err := vm.db.CommitBatch()
   515  	if err != nil {
   516  		t.Fatalf("Failed to create commit batch for VM due to %s", err)
   517  	}
   518  	if err := unsignedImportTx.Accept(vm.ctx, commitBatch); err != nil {
   519  		t.Fatalf("Accept failed due to: %s", err)
   520  	}
   521  
   522  	if err := unsignedImportTx.EVMStateTransfer(vm.ctx, state); err != nil {
   523  		t.Fatalf("EVM State Transfer failed due to: %s", err)
   524  	}
   525  
   526  	balance := state.GetBalance(testEthAddrs[0])
   527  	if balance == nil {
   528  		t.Fatal("Found nil balance for address receiving imported funds")
   529  	} else if balance.Uint64() != (importAmount-params.AvalancheAtomicTxFee)*x2cRate.Uint64() {
   530  		t.Fatalf("Balance was %d, but expected balance of: %d", balance.Uint64(), importAmount*x2cRate.Uint64())
   531  	}
   532  
   533  	// Check that SemanticVerify fails when the UTXO is not present after bootstrapping
   534  	if err := unsignedImportTx.SemanticVerify(vm, tx, parent, nil, apricotRulesPhase2); err == nil {
   535  		t.Fatal("Semantic verification should have failed after the UTXO removed from shared memory")
   536  	}
   537  }
   538  
   539  func TestNewImportTx(t *testing.T) {
   540  	tests := []struct {
   541  		name    string
   542  		genesis string
   543  		rules   params.Rules
   544  		bal     uint64
   545  	}{
   546  		{
   547  			name:    "apricot phase 0",
   548  			genesis: genesisJSONApricotPhase0,
   549  			rules:   apricotRulesPhase0,
   550  			bal:     5000000,
   551  		},
   552  		{
   553  			name:    "apricot phase 1",
   554  			genesis: genesisJSONApricotPhase1,
   555  			rules:   apricotRulesPhase1,
   556  			bal:     5000000,
   557  		},
   558  		{
   559  			name:    "apricot phase 2",
   560  			genesis: genesisJSONApricotPhase2,
   561  			rules:   apricotRulesPhase2,
   562  			bal:     4000000,
   563  		},
   564  		{
   565  			name:    "apricot phase 3",
   566  			genesis: genesisJSONApricotPhase3,
   567  			rules:   apricotRulesPhase3,
   568  			bal:     4723250,
   569  		},
   570  	}
   571  	for _, test := range tests {
   572  		t.Run(test.name, func(t *testing.T) {
   573  			_, vm, _, sharedMemory := GenesisVM(t, true, test.genesis, "", "")
   574  
   575  			defer func() {
   576  				if err := vm.Shutdown(); err != nil {
   577  					t.Fatal(err)
   578  				}
   579  			}()
   580  
   581  			parent := vm.LastAcceptedBlockInternal().(*Block)
   582  			importAmount := uint64(5000000)
   583  			utxoID := avax.UTXOID{
   584  				TxID: ids.ID{
   585  					0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   586  					0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   587  					0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   588  					0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   589  				},
   590  			}
   591  
   592  			utxo := &avax.UTXO{
   593  				UTXOID: utxoID,
   594  				Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
   595  				Out: &secp256k1fx.TransferOutput{
   596  					Amt: importAmount,
   597  					OutputOwners: secp256k1fx.OutputOwners{
   598  						Threshold: 1,
   599  						Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
   600  					},
   601  				},
   602  			}
   603  			utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
   604  			if err != nil {
   605  				t.Fatal(err)
   606  			}
   607  
   608  			xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
   609  			inputID := utxo.InputID()
   610  			if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{
   611  				Key:   inputID[:],
   612  				Value: utxoBytes,
   613  				Traits: [][]byte{
   614  					testKeys[0].PublicKey().Address().Bytes(),
   615  				},
   616  			}}}}); err != nil {
   617  				t.Fatal(err)
   618  			}
   619  
   620  			tx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
   621  			if err != nil {
   622  				t.Fatal(err)
   623  			}
   624  
   625  			importTx := tx.UnsignedAtomicTx
   626  
   627  			if err := importTx.SemanticVerify(vm, tx, parent, parent.ethBlock.BaseFee(), test.rules); err != nil {
   628  				t.Fatal("newImportTx created an invalid transaction", err)
   629  			}
   630  
   631  			commitBatch, err := vm.db.CommitBatch()
   632  			if err != nil {
   633  				t.Fatalf("Failed to create commit batch for VM due to %s", err)
   634  			}
   635  			if err := importTx.Accept(vm.ctx, commitBatch); err != nil {
   636  				t.Fatalf("Failed to accept import transaction due to: %s", err)
   637  			}
   638  
   639  			stdb, err := vm.chain.CurrentState()
   640  			if err != nil {
   641  				t.Fatal(err)
   642  			}
   643  			err = importTx.EVMStateTransfer(vm.ctx, stdb)
   644  			if err != nil {
   645  				t.Fatal(err)
   646  			}
   647  
   648  			addr := GetEthAddress(testKeys[0])
   649  			if stdb.GetBalance(addr).Cmp(new(big.Int).SetUint64(test.bal*units.Avax)) != 0 {
   650  				t.Fatalf("address balance %s equal %s not %s", addr.String(), stdb.GetBalance(addr), new(big.Int).SetUint64(test.bal*units.Avax))
   651  			}
   652  		})
   653  	}
   654  }
   655  
   656  // Note: this is a brittle test to ensure that the gas cost of a transaction does
   657  // not change
   658  func TestImportTxGasCost(t *testing.T) {
   659  	avaxAssetID := ids.GenerateTestID()
   660  	antAssetID := ids.GenerateTestID()
   661  	chainID := ids.GenerateTestID()
   662  	xChainID := ids.GenerateTestID()
   663  	networkID := uint32(5)
   664  	importAmount := uint64(5000000)
   665  
   666  	tests := map[string]struct {
   667  		UnsignedImportTx *UnsignedImportTx
   668  		Keys             [][]*crypto.PrivateKeySECP256K1R
   669  
   670  		ExpectedCost uint64
   671  		ExpectedFee  uint64
   672  		BaseFee      *big.Int
   673  	}{
   674  		"simple import": {
   675  			UnsignedImportTx: &UnsignedImportTx{
   676  				NetworkID:    networkID,
   677  				BlockchainID: chainID,
   678  				SourceChain:  xChainID,
   679  				ImportedInputs: []*avax.TransferableInput{{
   680  					UTXOID: avax.UTXOID{
   681  						TxID: ids.ID{
   682  							0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   683  							0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   684  							0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   685  							0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   686  						},
   687  					},
   688  					Asset: avax.Asset{ID: avaxAssetID},
   689  					In: &secp256k1fx.TransferInput{
   690  						Amt:   importAmount,
   691  						Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   692  					},
   693  				}},
   694  				Outs: []EVMOutput{{
   695  					Address: testEthAddrs[0],
   696  					Amount:  importAmount,
   697  					AssetID: avaxAssetID,
   698  				}},
   699  			},
   700  			Keys:         [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}},
   701  			ExpectedCost: 1230,
   702  			ExpectedFee:  30750,
   703  			BaseFee:      big.NewInt(25 * params.GWei),
   704  		},
   705  		"simple import 1wei": {
   706  			UnsignedImportTx: &UnsignedImportTx{
   707  				NetworkID:    networkID,
   708  				BlockchainID: chainID,
   709  				SourceChain:  xChainID,
   710  				ImportedInputs: []*avax.TransferableInput{{
   711  					UTXOID: avax.UTXOID{
   712  						TxID: ids.ID{
   713  							0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   714  							0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   715  							0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   716  							0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   717  						},
   718  					},
   719  					Asset: avax.Asset{ID: avaxAssetID},
   720  					In: &secp256k1fx.TransferInput{
   721  						Amt:   importAmount,
   722  						Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   723  					},
   724  				}},
   725  				Outs: []EVMOutput{{
   726  					Address: testEthAddrs[0],
   727  					Amount:  importAmount,
   728  					AssetID: avaxAssetID,
   729  				}},
   730  			},
   731  			Keys:         [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}},
   732  			ExpectedCost: 1230,
   733  			ExpectedFee:  1,
   734  			BaseFee:      big.NewInt(1),
   735  		},
   736  		"simple ANT import": {
   737  			UnsignedImportTx: &UnsignedImportTx{
   738  				NetworkID:    networkID,
   739  				BlockchainID: chainID,
   740  				SourceChain:  xChainID,
   741  				ImportedInputs: []*avax.TransferableInput{
   742  					{
   743  						UTXOID: avax.UTXOID{
   744  							TxID: ids.ID{
   745  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   746  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   747  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   748  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   749  							},
   750  						},
   751  						Asset: avax.Asset{ID: avaxAssetID},
   752  						In: &secp256k1fx.TransferInput{
   753  							Amt:   importAmount,
   754  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   755  						},
   756  					},
   757  					{
   758  						UTXOID: avax.UTXOID{
   759  							TxID: ids.ID{
   760  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   761  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   762  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   763  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe9,
   764  							},
   765  						},
   766  						Asset: avax.Asset{ID: antAssetID},
   767  						In: &secp256k1fx.TransferInput{
   768  							Amt:   importAmount,
   769  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   770  						},
   771  					},
   772  				},
   773  				Outs: []EVMOutput{
   774  					{
   775  						Address: testEthAddrs[0],
   776  						Amount:  importAmount,
   777  						AssetID: antAssetID,
   778  					},
   779  				},
   780  			},
   781  			Keys:         [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}, {testKeys[0]}},
   782  			ExpectedCost: 2318,
   783  			ExpectedFee:  57950,
   784  			BaseFee:      big.NewInt(25 * params.GWei),
   785  		},
   786  		"complex ANT import": {
   787  			UnsignedImportTx: &UnsignedImportTx{
   788  				NetworkID:    networkID,
   789  				BlockchainID: chainID,
   790  				SourceChain:  xChainID,
   791  				ImportedInputs: []*avax.TransferableInput{
   792  					{
   793  						UTXOID: avax.UTXOID{
   794  							TxID: ids.ID{
   795  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   796  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   797  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   798  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   799  							},
   800  						},
   801  						Asset: avax.Asset{ID: avaxAssetID},
   802  						In: &secp256k1fx.TransferInput{
   803  							Amt:   importAmount,
   804  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   805  						},
   806  					},
   807  					{
   808  						UTXOID: avax.UTXOID{
   809  							TxID: ids.ID{
   810  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   811  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   812  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   813  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe9,
   814  							},
   815  						},
   816  						Asset: avax.Asset{ID: antAssetID},
   817  						In: &secp256k1fx.TransferInput{
   818  							Amt:   importAmount,
   819  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   820  						},
   821  					},
   822  				},
   823  				Outs: []EVMOutput{
   824  					{
   825  						Address: testEthAddrs[0],
   826  						Amount:  importAmount,
   827  						AssetID: avaxAssetID,
   828  					},
   829  					{
   830  						Address: testEthAddrs[0],
   831  						Amount:  importAmount,
   832  						AssetID: antAssetID,
   833  					},
   834  				},
   835  			},
   836  			Keys:         [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}, {testKeys[0]}},
   837  			ExpectedCost: 2378,
   838  			ExpectedFee:  59450,
   839  			BaseFee:      big.NewInt(25 * params.GWei),
   840  		},
   841  		"multisig import": {
   842  			UnsignedImportTx: &UnsignedImportTx{
   843  				NetworkID:    networkID,
   844  				BlockchainID: chainID,
   845  				SourceChain:  xChainID,
   846  				ImportedInputs: []*avax.TransferableInput{{
   847  					UTXOID: avax.UTXOID{
   848  						TxID: ids.ID{
   849  							0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   850  							0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   851  							0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   852  							0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   853  						},
   854  					},
   855  					Asset: avax.Asset{ID: avaxAssetID},
   856  					In: &secp256k1fx.TransferInput{
   857  						Amt:   importAmount,
   858  						Input: secp256k1fx.Input{SigIndices: []uint32{0, 1}},
   859  					},
   860  				}},
   861  				Outs: []EVMOutput{{
   862  					Address: testEthAddrs[0],
   863  					Amount:  importAmount,
   864  					AssetID: avaxAssetID,
   865  				}},
   866  			},
   867  			Keys:         [][]*crypto.PrivateKeySECP256K1R{{testKeys[0], testKeys[1]}},
   868  			ExpectedCost: 2234,
   869  			ExpectedFee:  55850,
   870  			BaseFee:      big.NewInt(25 * params.GWei),
   871  		},
   872  		"large import": {
   873  			UnsignedImportTx: &UnsignedImportTx{
   874  				NetworkID:    networkID,
   875  				BlockchainID: chainID,
   876  				SourceChain:  xChainID,
   877  				ImportedInputs: []*avax.TransferableInput{
   878  					{
   879  						UTXOID: avax.UTXOID{
   880  							TxID: ids.ID{
   881  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   882  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   883  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   884  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa0,
   885  							},
   886  						},
   887  						Asset: avax.Asset{ID: avaxAssetID},
   888  						In: &secp256k1fx.TransferInput{
   889  							Amt:   importAmount,
   890  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   891  						},
   892  					},
   893  					{
   894  						UTXOID: avax.UTXOID{
   895  							TxID: ids.ID{
   896  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   897  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   898  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   899  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa1,
   900  							},
   901  						},
   902  						Asset: avax.Asset{ID: avaxAssetID},
   903  						In: &secp256k1fx.TransferInput{
   904  							Amt:   importAmount,
   905  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   906  						},
   907  					},
   908  					{
   909  						UTXOID: avax.UTXOID{
   910  							TxID: ids.ID{
   911  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   912  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   913  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   914  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa2,
   915  							},
   916  						},
   917  						Asset: avax.Asset{ID: avaxAssetID},
   918  						In: &secp256k1fx.TransferInput{
   919  							Amt:   importAmount,
   920  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   921  						},
   922  					},
   923  					{
   924  						UTXOID: avax.UTXOID{
   925  							TxID: ids.ID{
   926  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   927  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   928  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   929  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa3,
   930  							},
   931  						},
   932  						Asset: avax.Asset{ID: avaxAssetID},
   933  						In: &secp256k1fx.TransferInput{
   934  							Amt:   importAmount,
   935  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   936  						},
   937  					},
   938  					{
   939  						UTXOID: avax.UTXOID{
   940  							TxID: ids.ID{
   941  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   942  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   943  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   944  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa4,
   945  							},
   946  						},
   947  						Asset: avax.Asset{ID: avaxAssetID},
   948  						In: &secp256k1fx.TransferInput{
   949  							Amt:   importAmount,
   950  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   951  						},
   952  					},
   953  					{
   954  						UTXOID: avax.UTXOID{
   955  							TxID: ids.ID{
   956  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   957  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   958  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   959  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa5,
   960  							},
   961  						},
   962  						Asset: avax.Asset{ID: avaxAssetID},
   963  						In: &secp256k1fx.TransferInput{
   964  							Amt:   importAmount,
   965  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   966  						},
   967  					},
   968  					{
   969  						UTXOID: avax.UTXOID{
   970  							TxID: ids.ID{
   971  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   972  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   973  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   974  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa6,
   975  							},
   976  						},
   977  						Asset: avax.Asset{ID: avaxAssetID},
   978  						In: &secp256k1fx.TransferInput{
   979  							Amt:   importAmount,
   980  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   981  						},
   982  					},
   983  					{
   984  						UTXOID: avax.UTXOID{
   985  							TxID: ids.ID{
   986  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   987  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   988  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   989  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa7,
   990  							},
   991  						},
   992  						Asset: avax.Asset{ID: avaxAssetID},
   993  						In: &secp256k1fx.TransferInput{
   994  							Amt:   importAmount,
   995  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
   996  						},
   997  					},
   998  					{
   999  						UTXOID: avax.UTXOID{
  1000  							TxID: ids.ID{
  1001  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
  1002  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
  1003  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
  1004  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa8,
  1005  							},
  1006  						},
  1007  						Asset: avax.Asset{ID: avaxAssetID},
  1008  						In: &secp256k1fx.TransferInput{
  1009  							Amt:   importAmount,
  1010  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
  1011  						},
  1012  					},
  1013  					{
  1014  						UTXOID: avax.UTXOID{
  1015  							TxID: ids.ID{
  1016  								0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
  1017  								0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
  1018  								0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
  1019  								0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xa9,
  1020  							},
  1021  						},
  1022  						Asset: avax.Asset{ID: avaxAssetID},
  1023  						In: &secp256k1fx.TransferInput{
  1024  							Amt:   importAmount,
  1025  							Input: secp256k1fx.Input{SigIndices: []uint32{0}},
  1026  						},
  1027  					},
  1028  				},
  1029  				Outs: []EVMOutput{
  1030  					{
  1031  						Address: testEthAddrs[0],
  1032  						Amount:  importAmount * 10,
  1033  						AssetID: avaxAssetID,
  1034  					},
  1035  				},
  1036  			},
  1037  			Keys: [][]*crypto.PrivateKeySECP256K1R{
  1038  				{testKeys[0]},
  1039  				{testKeys[0]},
  1040  				{testKeys[0]},
  1041  				{testKeys[0]},
  1042  				{testKeys[0]},
  1043  				{testKeys[0]},
  1044  				{testKeys[0]},
  1045  				{testKeys[0]},
  1046  				{testKeys[0]},
  1047  				{testKeys[0]},
  1048  			},
  1049  			ExpectedCost: 11022,
  1050  			ExpectedFee:  275550,
  1051  			BaseFee:      big.NewInt(25 * params.GWei),
  1052  		},
  1053  	}
  1054  
  1055  	for name, test := range tests {
  1056  		t.Run(name, func(t *testing.T) {
  1057  			tx := &Tx{UnsignedAtomicTx: test.UnsignedImportTx}
  1058  
  1059  			// Sign with the correct key
  1060  			if err := tx.Sign(Codec, test.Keys); err != nil {
  1061  				t.Fatal(err)
  1062  			}
  1063  
  1064  			cost, err := tx.Cost()
  1065  			if err != nil {
  1066  				t.Fatal(err)
  1067  			}
  1068  			if cost != test.ExpectedCost {
  1069  				t.Fatalf("Expected cost to be %d, but found %d", test.ExpectedCost, cost)
  1070  			}
  1071  
  1072  			fee, err := calculateDynamicFee(cost, test.BaseFee)
  1073  			if err != nil {
  1074  				t.Fatal(err)
  1075  			}
  1076  			if fee != test.ExpectedFee {
  1077  				t.Fatalf("Expected fee to be %d, but found %d", test.ExpectedFee, fee)
  1078  			}
  1079  		})
  1080  	}
  1081  }