github.com/dim4egster/coreth@v0.10.2/plugin/evm/export_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  	"bytes"
     8  	"math/big"
     9  	"testing"
    10  
    11  	"github.com/dim4egster/qmallgo/chains/atomic"
    12  	"github.com/dim4egster/qmallgo/ids"
    13  	engCommon "github.com/dim4egster/qmallgo/snow/engine/common"
    14  	"github.com/dim4egster/qmallgo/utils/constants"
    15  	"github.com/dim4egster/qmallgo/utils/crypto"
    16  	"github.com/dim4egster/qmallgo/utils/units"
    17  	"github.com/dim4egster/qmallgo/vms/components/avax"
    18  	"github.com/dim4egster/qmallgo/vms/secp256k1fx"
    19  	"github.com/dim4egster/coreth/params"
    20  	"github.com/ethereum/go-ethereum/common"
    21  )
    22  
    23  // createExportTxOptions adds funds to shared memory, imports them, and returns a list of export transactions
    24  // that attempt to send the funds to each of the test keys (list of length 3).
    25  func createExportTxOptions(t *testing.T, vm *VM, issuer chan engCommon.Message, sharedMemory *atomic.Memory) []*Tx {
    26  	// Add a UTXO to shared memory
    27  	utxo := &avax.UTXO{
    28  		UTXOID: avax.UTXOID{TxID: ids.GenerateTestID()},
    29  		Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
    30  		Out: &secp256k1fx.TransferOutput{
    31  			Amt: uint64(50000000),
    32  			OutputOwners: secp256k1fx.OutputOwners{
    33  				Threshold: 1,
    34  				Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
    35  			},
    36  		},
    37  	}
    38  	utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  
    43  	xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
    44  	inputID := utxo.InputID()
    45  	if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{
    46  		Key:   inputID[:],
    47  		Value: utxoBytes,
    48  		Traits: [][]byte{
    49  			testKeys[0].PublicKey().Address().Bytes(),
    50  		},
    51  	}}}}); err != nil {
    52  		t.Fatal(err)
    53  	}
    54  
    55  	// Import the funds
    56  	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
    57  	if err != nil {
    58  		t.Fatal(err)
    59  	}
    60  
    61  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	<-issuer
    66  
    67  	blk, err := vm.BuildBlock()
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  
    72  	if err := blk.Verify(); err != nil {
    73  		t.Fatal(err)
    74  	}
    75  
    76  	if err := vm.SetPreference(blk.ID()); err != nil {
    77  		t.Fatal(err)
    78  	}
    79  
    80  	if err := blk.Accept(); err != nil {
    81  		t.Fatal(err)
    82  	}
    83  
    84  	// Use the funds to create 3 conflicting export transactions sending the funds to each of the test addresses
    85  	exportTxs := make([]*Tx, 0, 3)
    86  	for _, addr := range testShortIDAddrs {
    87  		exportTx, err := vm.newExportTx(vm.ctx.AVAXAssetID, uint64(5000000), vm.ctx.XChainID, addr, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
    88  		if err != nil {
    89  			t.Fatal(err)
    90  		}
    91  		exportTxs = append(exportTxs, exportTx)
    92  	}
    93  
    94  	return exportTxs
    95  }
    96  
    97  func TestExportTxEVMStateTransfer(t *testing.T) {
    98  	key := testKeys[0]
    99  	addr := key.PublicKey().Address()
   100  	ethAddr := GetEthAddress(key)
   101  
   102  	avaxAmount := 50 * units.MilliAvax
   103  	avaxUTXOID := avax.UTXOID{
   104  		OutputIndex: 0,
   105  	}
   106  	avaxInputID := avaxUTXOID.InputID()
   107  
   108  	customAmount := uint64(100)
   109  	customAssetID := ids.ID{1, 2, 3, 4, 5, 7}
   110  	customUTXOID := avax.UTXOID{
   111  		OutputIndex: 1,
   112  	}
   113  	customInputID := customUTXOID.InputID()
   114  
   115  	customUTXO := &avax.UTXO{
   116  		UTXOID: customUTXOID,
   117  		Asset:  avax.Asset{ID: customAssetID},
   118  		Out: &secp256k1fx.TransferOutput{
   119  			Amt: customAmount,
   120  			OutputOwners: secp256k1fx.OutputOwners{
   121  				Threshold: 1,
   122  				Addrs:     []ids.ShortID{addr},
   123  			},
   124  		},
   125  	}
   126  
   127  	tests := []struct {
   128  		name          string
   129  		tx            []EVMInput
   130  		avaxBalance   *big.Int
   131  		balances      map[ids.ID]*big.Int
   132  		expectedNonce uint64
   133  		shouldErr     bool
   134  	}{
   135  		{
   136  			name:        "no transfers",
   137  			tx:          nil,
   138  			avaxBalance: big.NewInt(int64(avaxAmount) * x2cRateInt64),
   139  			balances: map[ids.ID]*big.Int{
   140  				customAssetID: big.NewInt(int64(customAmount)),
   141  			},
   142  			expectedNonce: 0,
   143  			shouldErr:     false,
   144  		},
   145  		{
   146  			name: "spend half AVAX",
   147  			tx: []EVMInput{
   148  				{
   149  					Address: ethAddr,
   150  					Amount:  avaxAmount / 2,
   151  					AssetID: testAvaxAssetID,
   152  					Nonce:   0,
   153  				},
   154  			},
   155  			avaxBalance: big.NewInt(int64(avaxAmount/2) * x2cRateInt64),
   156  			balances: map[ids.ID]*big.Int{
   157  				customAssetID: big.NewInt(int64(customAmount)),
   158  			},
   159  			expectedNonce: 1,
   160  			shouldErr:     false,
   161  		},
   162  		{
   163  			name: "spend all AVAX",
   164  			tx: []EVMInput{
   165  				{
   166  					Address: ethAddr,
   167  					Amount:  avaxAmount,
   168  					AssetID: testAvaxAssetID,
   169  					Nonce:   0,
   170  				},
   171  			},
   172  			avaxBalance: big.NewInt(0),
   173  			balances: map[ids.ID]*big.Int{
   174  				customAssetID: big.NewInt(int64(customAmount)),
   175  			},
   176  			expectedNonce: 1,
   177  			shouldErr:     false,
   178  		},
   179  		{
   180  			name: "spend too much AVAX",
   181  			tx: []EVMInput{
   182  				{
   183  					Address: ethAddr,
   184  					Amount:  avaxAmount + 1,
   185  					AssetID: testAvaxAssetID,
   186  					Nonce:   0,
   187  				},
   188  			},
   189  			avaxBalance: big.NewInt(0),
   190  			balances: map[ids.ID]*big.Int{
   191  				customAssetID: big.NewInt(int64(customAmount)),
   192  			},
   193  			expectedNonce: 1,
   194  			shouldErr:     true,
   195  		},
   196  		{
   197  			name: "spend half custom",
   198  			tx: []EVMInput{
   199  				{
   200  					Address: ethAddr,
   201  					Amount:  customAmount / 2,
   202  					AssetID: customAssetID,
   203  					Nonce:   0,
   204  				},
   205  			},
   206  			avaxBalance: big.NewInt(int64(avaxAmount) * x2cRateInt64),
   207  			balances: map[ids.ID]*big.Int{
   208  				customAssetID: big.NewInt(int64(customAmount / 2)),
   209  			},
   210  			expectedNonce: 1,
   211  			shouldErr:     false,
   212  		},
   213  		{
   214  			name: "spend all custom",
   215  			tx: []EVMInput{
   216  				{
   217  					Address: ethAddr,
   218  					Amount:  customAmount,
   219  					AssetID: customAssetID,
   220  					Nonce:   0,
   221  				},
   222  			},
   223  			avaxBalance: big.NewInt(int64(avaxAmount) * x2cRateInt64),
   224  			balances: map[ids.ID]*big.Int{
   225  				customAssetID: big.NewInt(0),
   226  			},
   227  			expectedNonce: 1,
   228  			shouldErr:     false,
   229  		},
   230  		{
   231  			name: "spend too much custom",
   232  			tx: []EVMInput{
   233  				{
   234  					Address: ethAddr,
   235  					Amount:  customAmount + 1,
   236  					AssetID: customAssetID,
   237  					Nonce:   0,
   238  				},
   239  			},
   240  			avaxBalance: big.NewInt(int64(avaxAmount) * x2cRateInt64),
   241  			balances: map[ids.ID]*big.Int{
   242  				customAssetID: big.NewInt(0),
   243  			},
   244  			expectedNonce: 1,
   245  			shouldErr:     true,
   246  		},
   247  		{
   248  			name: "spend everything",
   249  			tx: []EVMInput{
   250  				{
   251  					Address: ethAddr,
   252  					Amount:  customAmount,
   253  					AssetID: customAssetID,
   254  					Nonce:   0,
   255  				},
   256  				{
   257  					Address: ethAddr,
   258  					Amount:  avaxAmount,
   259  					AssetID: testAvaxAssetID,
   260  					Nonce:   0,
   261  				},
   262  			},
   263  			avaxBalance: big.NewInt(0),
   264  			balances: map[ids.ID]*big.Int{
   265  				customAssetID: big.NewInt(0),
   266  			},
   267  			expectedNonce: 1,
   268  			shouldErr:     false,
   269  		},
   270  		{
   271  			name: "spend everything wrong nonce",
   272  			tx: []EVMInput{
   273  				{
   274  					Address: ethAddr,
   275  					Amount:  customAmount,
   276  					AssetID: customAssetID,
   277  					Nonce:   1,
   278  				},
   279  				{
   280  					Address: ethAddr,
   281  					Amount:  avaxAmount,
   282  					AssetID: testAvaxAssetID,
   283  					Nonce:   1,
   284  				},
   285  			},
   286  			avaxBalance: big.NewInt(0),
   287  			balances: map[ids.ID]*big.Int{
   288  				customAssetID: big.NewInt(0),
   289  			},
   290  			expectedNonce: 1,
   291  			shouldErr:     true,
   292  		},
   293  		{
   294  			name: "spend everything changing nonces",
   295  			tx: []EVMInput{
   296  				{
   297  					Address: ethAddr,
   298  					Amount:  customAmount,
   299  					AssetID: customAssetID,
   300  					Nonce:   0,
   301  				},
   302  				{
   303  					Address: ethAddr,
   304  					Amount:  avaxAmount,
   305  					AssetID: testAvaxAssetID,
   306  					Nonce:   1,
   307  				},
   308  			},
   309  			avaxBalance: big.NewInt(0),
   310  			balances: map[ids.ID]*big.Int{
   311  				customAssetID: big.NewInt(0),
   312  			},
   313  			expectedNonce: 1,
   314  			shouldErr:     true,
   315  		},
   316  	}
   317  	for _, test := range tests {
   318  		t.Run(test.name, func(t *testing.T) {
   319  			issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase0, "", "")
   320  			defer func() {
   321  				if err := vm.Shutdown(); err != nil {
   322  					t.Fatal(err)
   323  				}
   324  			}()
   325  
   326  			avaxUTXO := &avax.UTXO{
   327  				UTXOID: avaxUTXOID,
   328  				Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
   329  				Out: &secp256k1fx.TransferOutput{
   330  					Amt: avaxAmount,
   331  					OutputOwners: secp256k1fx.OutputOwners{
   332  						Threshold: 1,
   333  						Addrs:     []ids.ShortID{addr},
   334  					},
   335  				},
   336  			}
   337  
   338  			avaxUTXOBytes, err := vm.codec.Marshal(codecVersion, avaxUTXO)
   339  			if err != nil {
   340  				t.Fatal(err)
   341  			}
   342  
   343  			customUTXOBytes, err := vm.codec.Marshal(codecVersion, customUTXO)
   344  			if err != nil {
   345  				t.Fatal(err)
   346  			}
   347  
   348  			xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
   349  			if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{
   350  				{
   351  					Key:   avaxInputID[:],
   352  					Value: avaxUTXOBytes,
   353  					Traits: [][]byte{
   354  						addr.Bytes(),
   355  					},
   356  				},
   357  				{
   358  					Key:   customInputID[:],
   359  					Value: customUTXOBytes,
   360  					Traits: [][]byte{
   361  						addr.Bytes(),
   362  					},
   363  				},
   364  			}}}); err != nil {
   365  				t.Fatal(err)
   366  			}
   367  
   368  			tx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
   369  			if err != nil {
   370  				t.Fatal(err)
   371  			}
   372  
   373  			if err := vm.issueTx(tx, true /*=local*/); err != nil {
   374  				t.Fatal(err)
   375  			}
   376  
   377  			<-issuer
   378  
   379  			blk, err := vm.BuildBlock()
   380  			if err != nil {
   381  				t.Fatal(err)
   382  			}
   383  
   384  			if err := blk.Verify(); err != nil {
   385  				t.Fatal(err)
   386  			}
   387  
   388  			if err := vm.SetPreference(blk.ID()); err != nil {
   389  				t.Fatal(err)
   390  			}
   391  
   392  			if err := blk.Accept(); err != nil {
   393  				t.Fatal(err)
   394  			}
   395  
   396  			newTx := UnsignedExportTx{
   397  				Ins: test.tx,
   398  			}
   399  
   400  			stateDB, err := vm.blockChain.State()
   401  			if err != nil {
   402  				t.Fatal(err)
   403  			}
   404  
   405  			err = newTx.EVMStateTransfer(vm.ctx, stateDB)
   406  			if test.shouldErr {
   407  				if err == nil {
   408  					t.Fatal("expected EVMStateTransfer to fail")
   409  				}
   410  				return
   411  			}
   412  			if err != nil {
   413  				t.Fatal(err)
   414  			}
   415  
   416  			avaxBalance := stateDB.GetBalance(ethAddr)
   417  			if avaxBalance.Cmp(test.avaxBalance) != 0 {
   418  				t.Fatalf("address balance %s equal %s not %s", addr.String(), avaxBalance, test.avaxBalance)
   419  			}
   420  
   421  			for assetID, expectedBalance := range test.balances {
   422  				balance := stateDB.GetBalanceMultiCoin(ethAddr, common.Hash(assetID))
   423  				if avaxBalance.Cmp(test.avaxBalance) != 0 {
   424  					t.Fatalf("%s address balance %s equal %s not %s", assetID, addr.String(), balance, expectedBalance)
   425  				}
   426  			}
   427  
   428  			if stateDB.GetNonce(ethAddr) != test.expectedNonce {
   429  				t.Fatalf("failed to set nonce to %d", test.expectedNonce)
   430  			}
   431  		})
   432  	}
   433  }
   434  
   435  func TestExportTxSemanticVerify(t *testing.T) {
   436  	_, vm, _, _, _ := GenesisVM(t, true, genesisJSONApricotPhase0, "", "")
   437  
   438  	defer func() {
   439  		if err := vm.Shutdown(); err != nil {
   440  			t.Fatal(err)
   441  		}
   442  	}()
   443  
   444  	parent := vm.LastAcceptedBlockInternal().(*Block)
   445  
   446  	key := testKeys[0]
   447  	addr := key.PublicKey().Address()
   448  	ethAddr := testEthAddrs[0]
   449  
   450  	var (
   451  		avaxBalance           = 10 * units.Avax
   452  		custom0Balance uint64 = 100
   453  		custom0AssetID        = ids.ID{1, 2, 3, 4, 5}
   454  		custom1Balance uint64 = 1000
   455  		custom1AssetID        = ids.ID{1, 2, 3, 4, 5, 6}
   456  	)
   457  
   458  	validExportTx := &UnsignedExportTx{
   459  		NetworkID:        vm.ctx.NetworkID,
   460  		BlockchainID:     vm.ctx.ChainID,
   461  		DestinationChain: vm.ctx.XChainID,
   462  		Ins: []EVMInput{
   463  			{
   464  				Address: ethAddr,
   465  				Amount:  avaxBalance,
   466  				AssetID: vm.ctx.AVAXAssetID,
   467  				Nonce:   0,
   468  			},
   469  			{
   470  				Address: ethAddr,
   471  				Amount:  custom0Balance,
   472  				AssetID: custom0AssetID,
   473  				Nonce:   0,
   474  			},
   475  			{
   476  				Address: ethAddr,
   477  				Amount:  custom1Balance,
   478  				AssetID: custom1AssetID,
   479  				Nonce:   0,
   480  			},
   481  		},
   482  		ExportedOutputs: []*avax.TransferableOutput{
   483  			{
   484  				Asset: avax.Asset{ID: custom0AssetID},
   485  				Out: &secp256k1fx.TransferOutput{
   486  					Amt: custom0Balance,
   487  					OutputOwners: secp256k1fx.OutputOwners{
   488  						Threshold: 1,
   489  						Addrs:     []ids.ShortID{addr},
   490  					},
   491  				},
   492  			},
   493  		},
   494  	}
   495  
   496  	validAVAXExportTx := &UnsignedExportTx{
   497  		NetworkID:        vm.ctx.NetworkID,
   498  		BlockchainID:     vm.ctx.ChainID,
   499  		DestinationChain: vm.ctx.XChainID,
   500  		Ins: []EVMInput{
   501  			{
   502  				Address: ethAddr,
   503  				Amount:  avaxBalance,
   504  				AssetID: vm.ctx.AVAXAssetID,
   505  				Nonce:   0,
   506  			},
   507  		},
   508  		ExportedOutputs: []*avax.TransferableOutput{
   509  			{
   510  				Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
   511  				Out: &secp256k1fx.TransferOutput{
   512  					Amt: avaxBalance / 2,
   513  					OutputOwners: secp256k1fx.OutputOwners{
   514  						Threshold: 1,
   515  						Addrs:     []ids.ShortID{addr},
   516  					},
   517  				},
   518  			},
   519  		},
   520  	}
   521  
   522  	tests := []struct {
   523  		name      string
   524  		tx        *Tx
   525  		signers   [][]*crypto.PrivateKeySECP256K1R
   526  		baseFee   *big.Int
   527  		rules     params.Rules
   528  		shouldErr bool
   529  	}{
   530  		{
   531  			name: "valid",
   532  			tx:   &Tx{UnsignedAtomicTx: validExportTx},
   533  			signers: [][]*crypto.PrivateKeySECP256K1R{
   534  				{key},
   535  				{key},
   536  				{key},
   537  			},
   538  			baseFee:   initialBaseFee,
   539  			rules:     apricotRulesPhase3,
   540  			shouldErr: false,
   541  		},
   542  		{
   543  			name: "P-chain before AP5",
   544  			tx: func() *Tx {
   545  				validExportTx := *validAVAXExportTx
   546  				validExportTx.DestinationChain = constants.PlatformChainID
   547  				return &Tx{UnsignedAtomicTx: &validExportTx}
   548  			}(),
   549  			signers: [][]*crypto.PrivateKeySECP256K1R{
   550  				{key},
   551  			},
   552  			baseFee:   initialBaseFee,
   553  			rules:     apricotRulesPhase3,
   554  			shouldErr: true,
   555  		},
   556  		{
   557  			name: "P-chain after AP5",
   558  			tx: func() *Tx {
   559  				validExportTx := *validAVAXExportTx
   560  				validExportTx.DestinationChain = constants.PlatformChainID
   561  				return &Tx{UnsignedAtomicTx: &validExportTx}
   562  			}(),
   563  			signers: [][]*crypto.PrivateKeySECP256K1R{
   564  				{key},
   565  			},
   566  			baseFee:   initialBaseFee,
   567  			rules:     apricotRulesPhase5,
   568  			shouldErr: false,
   569  		},
   570  		{
   571  			name: "random chain after AP5",
   572  			tx: func() *Tx {
   573  				validExportTx := *validAVAXExportTx
   574  				validExportTx.DestinationChain = ids.GenerateTestID()
   575  				return &Tx{UnsignedAtomicTx: &validExportTx}
   576  			}(),
   577  			signers: [][]*crypto.PrivateKeySECP256K1R{
   578  				{key},
   579  			},
   580  			baseFee:   initialBaseFee,
   581  			rules:     apricotRulesPhase5,
   582  			shouldErr: true,
   583  		},
   584  		{
   585  			name: "P-chain multi-coin before AP5",
   586  			tx: func() *Tx {
   587  				validExportTx := *validExportTx
   588  				validExportTx.DestinationChain = constants.PlatformChainID
   589  				return &Tx{UnsignedAtomicTx: &validExportTx}
   590  			}(),
   591  			signers: [][]*crypto.PrivateKeySECP256K1R{
   592  				{key},
   593  				{key},
   594  				{key},
   595  			},
   596  			baseFee:   initialBaseFee,
   597  			rules:     apricotRulesPhase3,
   598  			shouldErr: true,
   599  		},
   600  		{
   601  			name: "P-chain multi-coin after AP5",
   602  			tx: func() *Tx {
   603  				validExportTx := *validExportTx
   604  				validExportTx.DestinationChain = constants.PlatformChainID
   605  				return &Tx{UnsignedAtomicTx: &validExportTx}
   606  			}(),
   607  			signers: [][]*crypto.PrivateKeySECP256K1R{
   608  				{key},
   609  				{key},
   610  				{key},
   611  			},
   612  			baseFee:   initialBaseFee,
   613  			rules:     apricotRulesPhase5,
   614  			shouldErr: true,
   615  		},
   616  		{
   617  			name: "random chain multi-coin  after AP5",
   618  			tx: func() *Tx {
   619  				validExportTx := *validExportTx
   620  				validExportTx.DestinationChain = ids.GenerateTestID()
   621  				return &Tx{UnsignedAtomicTx: &validExportTx}
   622  			}(),
   623  			signers: [][]*crypto.PrivateKeySECP256K1R{
   624  				{key},
   625  				{key},
   626  				{key},
   627  			},
   628  			baseFee:   initialBaseFee,
   629  			rules:     apricotRulesPhase5,
   630  			shouldErr: true,
   631  		},
   632  		{
   633  			name: "no outputs",
   634  			tx: func() *Tx {
   635  				validExportTx := *validExportTx
   636  				validExportTx.ExportedOutputs = nil
   637  				return &Tx{UnsignedAtomicTx: &validExportTx}
   638  			}(),
   639  			signers: [][]*crypto.PrivateKeySECP256K1R{
   640  				{key},
   641  				{key},
   642  				{key},
   643  			},
   644  			baseFee:   initialBaseFee,
   645  			rules:     apricotRulesPhase3,
   646  			shouldErr: true,
   647  		},
   648  		{
   649  			name: "wrong networkID",
   650  			tx: func() *Tx {
   651  				validExportTx := *validExportTx
   652  				validExportTx.NetworkID++
   653  				return &Tx{UnsignedAtomicTx: &validExportTx}
   654  			}(),
   655  			signers: [][]*crypto.PrivateKeySECP256K1R{
   656  				{key},
   657  				{key},
   658  				{key},
   659  			},
   660  			baseFee:   initialBaseFee,
   661  			rules:     apricotRulesPhase3,
   662  			shouldErr: true,
   663  		},
   664  		{
   665  			name: "wrong chainID",
   666  			tx: func() *Tx {
   667  				validExportTx := *validExportTx
   668  				validExportTx.BlockchainID = ids.GenerateTestID()
   669  				return &Tx{UnsignedAtomicTx: &validExportTx}
   670  			}(),
   671  			signers: [][]*crypto.PrivateKeySECP256K1R{
   672  				{key},
   673  				{key},
   674  				{key},
   675  			},
   676  			baseFee:   initialBaseFee,
   677  			rules:     apricotRulesPhase3,
   678  			shouldErr: true,
   679  		},
   680  		{
   681  			name: "invalid input",
   682  			tx: func() *Tx {
   683  				validExportTx := *validExportTx
   684  				validExportTx.Ins = append([]EVMInput{}, validExportTx.Ins...)
   685  				validExportTx.Ins[2].Amount = 0
   686  				return &Tx{UnsignedAtomicTx: &validExportTx}
   687  			}(),
   688  			signers: [][]*crypto.PrivateKeySECP256K1R{
   689  				{key},
   690  				{key},
   691  				{key},
   692  			},
   693  			baseFee:   initialBaseFee,
   694  			rules:     apricotRulesPhase3,
   695  			shouldErr: true,
   696  		},
   697  		{
   698  			name: "invalid output",
   699  			tx: func() *Tx {
   700  				validExportTx := *validExportTx
   701  				validExportTx.ExportedOutputs = []*avax.TransferableOutput{{
   702  					Asset: avax.Asset{ID: custom0AssetID},
   703  					Out: &secp256k1fx.TransferOutput{
   704  						Amt: custom0Balance,
   705  						OutputOwners: secp256k1fx.OutputOwners{
   706  							Threshold: 0,
   707  							Addrs:     []ids.ShortID{addr},
   708  						},
   709  					},
   710  				}}
   711  				return &Tx{UnsignedAtomicTx: &validExportTx}
   712  			}(),
   713  			signers: [][]*crypto.PrivateKeySECP256K1R{
   714  				{key},
   715  				{key},
   716  				{key},
   717  			},
   718  			baseFee:   initialBaseFee,
   719  			rules:     apricotRulesPhase3,
   720  			shouldErr: true,
   721  		},
   722  		{
   723  			name: "unsorted outputs",
   724  			tx: func() *Tx {
   725  				validExportTx := *validExportTx
   726  				exportOutputs := []*avax.TransferableOutput{
   727  					{
   728  						Asset: avax.Asset{ID: custom0AssetID},
   729  						Out: &secp256k1fx.TransferOutput{
   730  							Amt: custom0Balance/2 + 1,
   731  							OutputOwners: secp256k1fx.OutputOwners{
   732  								Threshold: 1,
   733  								Addrs:     []ids.ShortID{addr},
   734  							},
   735  						},
   736  					},
   737  					{
   738  						Asset: avax.Asset{ID: custom0AssetID},
   739  						Out: &secp256k1fx.TransferOutput{
   740  							Amt: custom0Balance/2 - 1,
   741  							OutputOwners: secp256k1fx.OutputOwners{
   742  								Threshold: 1,
   743  								Addrs:     []ids.ShortID{addr},
   744  							},
   745  						},
   746  					},
   747  				}
   748  				// Sort the outputs and then swap the ordering to ensure that they are ordered incorrectly
   749  				avax.SortTransferableOutputs(exportOutputs, Codec)
   750  				exportOutputs[0], exportOutputs[1] = exportOutputs[1], exportOutputs[0]
   751  				validExportTx.ExportedOutputs = exportOutputs
   752  				return &Tx{UnsignedAtomicTx: &validExportTx}
   753  			}(),
   754  			signers: [][]*crypto.PrivateKeySECP256K1R{
   755  				{key},
   756  				{key},
   757  				{key},
   758  			},
   759  			baseFee:   initialBaseFee,
   760  			rules:     apricotRulesPhase3,
   761  			shouldErr: true,
   762  		},
   763  		{
   764  			name: "not unique inputs",
   765  			tx: func() *Tx {
   766  				validExportTx := *validExportTx
   767  				validExportTx.Ins = append([]EVMInput{}, validExportTx.Ins...)
   768  				validExportTx.Ins[2] = validExportTx.Ins[1]
   769  				return &Tx{UnsignedAtomicTx: &validExportTx}
   770  			}(),
   771  			signers: [][]*crypto.PrivateKeySECP256K1R{
   772  				{key},
   773  				{key},
   774  				{key},
   775  			},
   776  			baseFee:   initialBaseFee,
   777  			rules:     apricotRulesPhase3,
   778  			shouldErr: true,
   779  		},
   780  		{
   781  			name: "custom asset insufficient funds",
   782  			tx: func() *Tx {
   783  				validExportTx := *validExportTx
   784  				validExportTx.ExportedOutputs = []*avax.TransferableOutput{
   785  					{
   786  						Asset: avax.Asset{ID: custom0AssetID},
   787  						Out: &secp256k1fx.TransferOutput{
   788  							Amt: custom0Balance + 1,
   789  							OutputOwners: secp256k1fx.OutputOwners{
   790  								Threshold: 1,
   791  								Addrs:     []ids.ShortID{addr},
   792  							},
   793  						},
   794  					},
   795  				}
   796  				return &Tx{UnsignedAtomicTx: &validExportTx}
   797  			}(),
   798  			signers: [][]*crypto.PrivateKeySECP256K1R{
   799  				{key},
   800  				{key},
   801  				{key},
   802  			},
   803  			baseFee:   initialBaseFee,
   804  			rules:     apricotRulesPhase3,
   805  			shouldErr: true,
   806  		},
   807  		{
   808  			name: "avax insufficient funds",
   809  			tx: func() *Tx {
   810  				validExportTx := *validExportTx
   811  				validExportTx.ExportedOutputs = []*avax.TransferableOutput{
   812  					{
   813  						Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
   814  						Out: &secp256k1fx.TransferOutput{
   815  							Amt: avaxBalance, // after fees this should be too much
   816  							OutputOwners: secp256k1fx.OutputOwners{
   817  								Threshold: 1,
   818  								Addrs:     []ids.ShortID{addr},
   819  							},
   820  						},
   821  					},
   822  				}
   823  				return &Tx{UnsignedAtomicTx: &validExportTx}
   824  			}(),
   825  			signers: [][]*crypto.PrivateKeySECP256K1R{
   826  				{key},
   827  				{key},
   828  				{key},
   829  			},
   830  			baseFee:   initialBaseFee,
   831  			rules:     apricotRulesPhase3,
   832  			shouldErr: true,
   833  		},
   834  		{
   835  			name: "too many signatures",
   836  			tx:   &Tx{UnsignedAtomicTx: validExportTx},
   837  			signers: [][]*crypto.PrivateKeySECP256K1R{
   838  				{key},
   839  				{key},
   840  				{key},
   841  				{key},
   842  			},
   843  			baseFee:   initialBaseFee,
   844  			rules:     apricotRulesPhase3,
   845  			shouldErr: true,
   846  		},
   847  		{
   848  			name: "too few signatures",
   849  			tx:   &Tx{UnsignedAtomicTx: validExportTx},
   850  			signers: [][]*crypto.PrivateKeySECP256K1R{
   851  				{key},
   852  				{key},
   853  			},
   854  			baseFee:   initialBaseFee,
   855  			rules:     apricotRulesPhase3,
   856  			shouldErr: true,
   857  		},
   858  		{
   859  			name: "too many signatures on credential",
   860  			tx:   &Tx{UnsignedAtomicTx: validExportTx},
   861  			signers: [][]*crypto.PrivateKeySECP256K1R{
   862  				{key, testKeys[1]},
   863  				{key},
   864  				{key},
   865  			},
   866  			baseFee:   initialBaseFee,
   867  			rules:     apricotRulesPhase3,
   868  			shouldErr: true,
   869  		},
   870  		{
   871  			name: "too few signatures on credential",
   872  			tx:   &Tx{UnsignedAtomicTx: validExportTx},
   873  			signers: [][]*crypto.PrivateKeySECP256K1R{
   874  				{},
   875  				{key},
   876  				{key},
   877  			},
   878  			baseFee:   initialBaseFee,
   879  			rules:     apricotRulesPhase3,
   880  			shouldErr: true,
   881  		},
   882  		{
   883  			name: "wrong signature on credential",
   884  			tx:   &Tx{UnsignedAtomicTx: validExportTx},
   885  			signers: [][]*crypto.PrivateKeySECP256K1R{
   886  				{testKeys[1]},
   887  				{key},
   888  				{key},
   889  			},
   890  			baseFee:   initialBaseFee,
   891  			rules:     apricotRulesPhase3,
   892  			shouldErr: true,
   893  		},
   894  		{
   895  			name:      "no signatures",
   896  			tx:        &Tx{UnsignedAtomicTx: validExportTx},
   897  			signers:   [][]*crypto.PrivateKeySECP256K1R{},
   898  			baseFee:   initialBaseFee,
   899  			rules:     apricotRulesPhase3,
   900  			shouldErr: true,
   901  		},
   902  	}
   903  	for _, test := range tests {
   904  		if err := test.tx.Sign(vm.codec, test.signers); err != nil {
   905  			t.Fatal(err)
   906  		}
   907  
   908  		t.Run(test.name, func(t *testing.T) {
   909  			tx := test.tx
   910  			exportTx := tx.UnsignedAtomicTx
   911  
   912  			err := exportTx.SemanticVerify(vm, tx, parent, test.baseFee, test.rules)
   913  			if test.shouldErr && err == nil {
   914  				t.Fatalf("should have errored but returned valid")
   915  			}
   916  			if !test.shouldErr && err != nil {
   917  				t.Fatalf("shouldn't have errored but returned %s", err)
   918  			}
   919  		})
   920  	}
   921  }
   922  
   923  func TestExportTxAccept(t *testing.T) {
   924  	_, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase0, "", "")
   925  
   926  	xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
   927  
   928  	defer func() {
   929  		if err := vm.Shutdown(); err != nil {
   930  			t.Fatal(err)
   931  		}
   932  	}()
   933  
   934  	key := testKeys[0]
   935  	addr := key.PublicKey().Address()
   936  	ethAddr := testEthAddrs[0]
   937  
   938  	var (
   939  		avaxBalance           = 10 * units.Avax
   940  		custom0Balance uint64 = 100
   941  		custom0AssetID        = ids.ID{1, 2, 3, 4, 5}
   942  	)
   943  
   944  	exportTx := &UnsignedExportTx{
   945  		NetworkID:        vm.ctx.NetworkID,
   946  		BlockchainID:     vm.ctx.ChainID,
   947  		DestinationChain: vm.ctx.XChainID,
   948  		Ins: []EVMInput{
   949  			{
   950  				Address: ethAddr,
   951  				Amount:  avaxBalance,
   952  				AssetID: vm.ctx.AVAXAssetID,
   953  				Nonce:   0,
   954  			},
   955  			{
   956  				Address: ethAddr,
   957  				Amount:  custom0Balance,
   958  				AssetID: custom0AssetID,
   959  				Nonce:   0,
   960  			},
   961  		},
   962  		ExportedOutputs: []*avax.TransferableOutput{
   963  			{
   964  				Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
   965  				Out: &secp256k1fx.TransferOutput{
   966  					Amt: avaxBalance,
   967  					OutputOwners: secp256k1fx.OutputOwners{
   968  						Threshold: 1,
   969  						Addrs:     []ids.ShortID{addr},
   970  					},
   971  				},
   972  			},
   973  			{
   974  				Asset: avax.Asset{ID: custom0AssetID},
   975  				Out: &secp256k1fx.TransferOutput{
   976  					Amt: custom0Balance,
   977  					OutputOwners: secp256k1fx.OutputOwners{
   978  						Threshold: 1,
   979  						Addrs:     []ids.ShortID{addr},
   980  					},
   981  				},
   982  			},
   983  		},
   984  	}
   985  
   986  	tx := &Tx{UnsignedAtomicTx: exportTx}
   987  
   988  	signers := [][]*crypto.PrivateKeySECP256K1R{
   989  		{key},
   990  		{key},
   991  		{key},
   992  	}
   993  
   994  	if err := tx.Sign(vm.codec, signers); err != nil {
   995  		t.Fatal(err)
   996  	}
   997  
   998  	commitBatch, err := vm.db.CommitBatch()
   999  	if err != nil {
  1000  		t.Fatalf("Failed to create commit batch for VM due to %s", err)
  1001  	}
  1002  	chainID, atomicRequests, err := tx.AtomicOps()
  1003  	if err != nil {
  1004  		t.Fatalf("Failed to accept export transaction due to: %s", err)
  1005  	}
  1006  
  1007  	if err := vm.ctx.SharedMemory.Apply(map[ids.ID]*atomic.Requests{chainID: {PutRequests: atomicRequests.PutRequests}}, commitBatch); err != nil {
  1008  		t.Fatal(err)
  1009  	}
  1010  	indexedValues, _, _, err := xChainSharedMemory.Indexed(vm.ctx.ChainID, [][]byte{addr.Bytes()}, nil, nil, 3)
  1011  	if err != nil {
  1012  		t.Fatal(err)
  1013  	}
  1014  
  1015  	if len(indexedValues) != 2 {
  1016  		t.Fatalf("expected 2 values but got %d", len(indexedValues))
  1017  	}
  1018  
  1019  	avaxUTXOID := avax.UTXOID{
  1020  		TxID:        tx.ID(),
  1021  		OutputIndex: 0,
  1022  	}
  1023  	avaxInputID := avaxUTXOID.InputID()
  1024  
  1025  	customUTXOID := avax.UTXOID{
  1026  		TxID:        tx.ID(),
  1027  		OutputIndex: 1,
  1028  	}
  1029  	customInputID := customUTXOID.InputID()
  1030  
  1031  	fetchedValues, err := xChainSharedMemory.Get(vm.ctx.ChainID, [][]byte{
  1032  		customInputID[:],
  1033  		avaxInputID[:],
  1034  	})
  1035  	if err != nil {
  1036  		t.Fatal(err)
  1037  	}
  1038  
  1039  	if !bytes.Equal(fetchedValues[0], indexedValues[0]) {
  1040  		t.Fatalf("inconsistent values returned fetched %x indexed %x", fetchedValues[0], indexedValues[0])
  1041  	}
  1042  	if !bytes.Equal(fetchedValues[1], indexedValues[1]) {
  1043  		t.Fatalf("inconsistent values returned fetched %x indexed %x", fetchedValues[1], indexedValues[1])
  1044  	}
  1045  
  1046  	customUTXOBytes, err := Codec.Marshal(codecVersion, &avax.UTXO{
  1047  		UTXOID: customUTXOID,
  1048  		Asset:  avax.Asset{ID: custom0AssetID},
  1049  		Out:    exportTx.ExportedOutputs[1].Out,
  1050  	})
  1051  	if err != nil {
  1052  		t.Fatal(err)
  1053  	}
  1054  
  1055  	avaxUTXOBytes, err := Codec.Marshal(codecVersion, &avax.UTXO{
  1056  		UTXOID: avaxUTXOID,
  1057  		Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
  1058  		Out:    exportTx.ExportedOutputs[0].Out,
  1059  	})
  1060  	if err != nil {
  1061  		t.Fatal(err)
  1062  	}
  1063  
  1064  	if !bytes.Equal(fetchedValues[0], customUTXOBytes) {
  1065  		t.Fatalf("incorrect values returned expected %x got %x", customUTXOBytes, fetchedValues[0])
  1066  	}
  1067  	if !bytes.Equal(fetchedValues[1], avaxUTXOBytes) {
  1068  		t.Fatalf("incorrect values returned expected %x got %x", avaxUTXOBytes, fetchedValues[1])
  1069  	}
  1070  }
  1071  
  1072  func TestExportTxVerify(t *testing.T) {
  1073  	var exportAmount uint64 = 10000000
  1074  	exportTx := &UnsignedExportTx{
  1075  		NetworkID:        testNetworkID,
  1076  		BlockchainID:     testCChainID,
  1077  		DestinationChain: testXChainID,
  1078  		Ins: []EVMInput{
  1079  			{
  1080  				Address: testEthAddrs[0],
  1081  				Amount:  exportAmount,
  1082  				AssetID: testAvaxAssetID,
  1083  				Nonce:   0,
  1084  			},
  1085  			{
  1086  				Address: testEthAddrs[2],
  1087  				Amount:  exportAmount,
  1088  				AssetID: testAvaxAssetID,
  1089  				Nonce:   0,
  1090  			},
  1091  		},
  1092  		ExportedOutputs: []*avax.TransferableOutput{
  1093  			{
  1094  				Asset: avax.Asset{ID: testAvaxAssetID},
  1095  				Out: &secp256k1fx.TransferOutput{
  1096  					Amt: exportAmount,
  1097  					OutputOwners: secp256k1fx.OutputOwners{
  1098  						Locktime:  0,
  1099  						Threshold: 1,
  1100  						Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1101  					},
  1102  				},
  1103  			},
  1104  			{
  1105  				Asset: avax.Asset{ID: testAvaxAssetID},
  1106  				Out: &secp256k1fx.TransferOutput{
  1107  					Amt: exportAmount,
  1108  					OutputOwners: secp256k1fx.OutputOwners{
  1109  						Locktime:  0,
  1110  						Threshold: 1,
  1111  						Addrs:     []ids.ShortID{testShortIDAddrs[1]},
  1112  					},
  1113  				},
  1114  			},
  1115  		},
  1116  	}
  1117  
  1118  	// Sort the inputs and outputs to ensure the transaction is canonical
  1119  	avax.SortTransferableOutputs(exportTx.ExportedOutputs, Codec)
  1120  	// Pass in a list of signers here with the appropriate length
  1121  	// to avoid causing a nil-pointer error in the helper method
  1122  	emptySigners := make([][]*crypto.PrivateKeySECP256K1R, 2)
  1123  	SortEVMInputsAndSigners(exportTx.Ins, emptySigners)
  1124  
  1125  	ctx := NewContext()
  1126  
  1127  	tests := map[string]atomicTxVerifyTest{
  1128  		"nil tx": {
  1129  			generate: func(t *testing.T) UnsignedAtomicTx {
  1130  				return (*UnsignedExportTx)(nil)
  1131  			},
  1132  			ctx:         ctx,
  1133  			rules:       apricotRulesPhase0,
  1134  			expectedErr: errNilTx.Error(),
  1135  		},
  1136  		"valid export tx": {
  1137  			generate: func(t *testing.T) UnsignedAtomicTx {
  1138  				return exportTx
  1139  			},
  1140  			ctx:         ctx,
  1141  			rules:       apricotRulesPhase0,
  1142  			expectedErr: "",
  1143  		},
  1144  		"valid export tx banff": {
  1145  			generate: func(t *testing.T) UnsignedAtomicTx {
  1146  				return exportTx
  1147  			},
  1148  			ctx:         ctx,
  1149  			rules:       banffRules,
  1150  			expectedErr: "",
  1151  		},
  1152  		"incorrect networkID": {
  1153  			generate: func(t *testing.T) UnsignedAtomicTx {
  1154  				tx := *exportTx
  1155  				tx.NetworkID++
  1156  				return &tx
  1157  			},
  1158  			ctx:         ctx,
  1159  			rules:       apricotRulesPhase0,
  1160  			expectedErr: errWrongNetworkID.Error(),
  1161  		},
  1162  		"incorrect blockchainID": {
  1163  			generate: func(t *testing.T) UnsignedAtomicTx {
  1164  				tx := *exportTx
  1165  				tx.BlockchainID = nonExistentID
  1166  				return &tx
  1167  			},
  1168  			ctx:         ctx,
  1169  			rules:       apricotRulesPhase0,
  1170  			expectedErr: errWrongBlockchainID.Error(),
  1171  		},
  1172  		"incorrect destination chain": {
  1173  			generate: func(t *testing.T) UnsignedAtomicTx {
  1174  				tx := *exportTx
  1175  				tx.DestinationChain = nonExistentID
  1176  				return &tx
  1177  			},
  1178  			ctx:         ctx,
  1179  			rules:       apricotRulesPhase0,
  1180  			expectedErr: errWrongChainID.Error(), // TODO make this error more specific to destination not just chainID
  1181  		},
  1182  		"no exported outputs": {
  1183  			generate: func(t *testing.T) UnsignedAtomicTx {
  1184  				tx := *exportTx
  1185  				tx.ExportedOutputs = nil
  1186  				return &tx
  1187  			},
  1188  			ctx:         ctx,
  1189  			rules:       apricotRulesPhase0,
  1190  			expectedErr: errNoExportOutputs.Error(),
  1191  		},
  1192  		"unsorted outputs": {
  1193  			generate: func(t *testing.T) UnsignedAtomicTx {
  1194  				tx := *exportTx
  1195  				tx.ExportedOutputs = []*avax.TransferableOutput{
  1196  					tx.ExportedOutputs[1],
  1197  					tx.ExportedOutputs[0],
  1198  				}
  1199  				return &tx
  1200  			},
  1201  			ctx:         ctx,
  1202  			rules:       apricotRulesPhase0,
  1203  			expectedErr: errOutputsNotSorted.Error(),
  1204  		},
  1205  		"invalid exported output": {
  1206  			generate: func(t *testing.T) UnsignedAtomicTx {
  1207  				tx := *exportTx
  1208  				tx.ExportedOutputs = []*avax.TransferableOutput{tx.ExportedOutputs[0], nil}
  1209  				return &tx
  1210  			},
  1211  			ctx:         ctx,
  1212  			rules:       apricotRulesPhase0,
  1213  			expectedErr: "nil transferable output is not valid",
  1214  		},
  1215  		"unsorted EVM inputs before AP1": {
  1216  			generate: func(t *testing.T) UnsignedAtomicTx {
  1217  				tx := *exportTx
  1218  				tx.Ins = []EVMInput{
  1219  					tx.Ins[1],
  1220  					tx.Ins[0],
  1221  				}
  1222  				return &tx
  1223  			},
  1224  			ctx:         ctx,
  1225  			rules:       apricotRulesPhase0,
  1226  			expectedErr: "",
  1227  		},
  1228  		"unsorted EVM inputs after AP1": {
  1229  			generate: func(t *testing.T) UnsignedAtomicTx {
  1230  				tx := *exportTx
  1231  				tx.Ins = []EVMInput{
  1232  					tx.Ins[1],
  1233  					tx.Ins[0],
  1234  				}
  1235  				return &tx
  1236  			},
  1237  			ctx:         ctx,
  1238  			rules:       apricotRulesPhase1,
  1239  			expectedErr: errInputsNotSortedUnique.Error(),
  1240  		},
  1241  		"EVM input with amount 0": {
  1242  			generate: func(t *testing.T) UnsignedAtomicTx {
  1243  				tx := *exportTx
  1244  				tx.Ins = []EVMInput{
  1245  					{
  1246  						Address: testEthAddrs[0],
  1247  						Amount:  0,
  1248  						AssetID: testAvaxAssetID,
  1249  						Nonce:   0,
  1250  					},
  1251  				}
  1252  				return &tx
  1253  			},
  1254  			ctx:         ctx,
  1255  			rules:       apricotRulesPhase0,
  1256  			expectedErr: errNoValueInput.Error(),
  1257  		},
  1258  		"non-unique EVM input before AP1": {
  1259  			generate: func(t *testing.T) UnsignedAtomicTx {
  1260  				tx := *exportTx
  1261  				tx.Ins = []EVMInput{tx.Ins[0], tx.Ins[0]}
  1262  				return &tx
  1263  			},
  1264  			ctx:         ctx,
  1265  			rules:       apricotRulesPhase0,
  1266  			expectedErr: "",
  1267  		},
  1268  		"non-unique EVM input after AP1": {
  1269  			generate: func(t *testing.T) UnsignedAtomicTx {
  1270  				tx := *exportTx
  1271  				tx.Ins = []EVMInput{tx.Ins[0], tx.Ins[0]}
  1272  				return &tx
  1273  			},
  1274  			ctx:         ctx,
  1275  			rules:       apricotRulesPhase1,
  1276  			expectedErr: errInputsNotSortedUnique.Error(),
  1277  		},
  1278  		"non-AVAX input Apricot Phase 6": {
  1279  			generate: func(t *testing.T) UnsignedAtomicTx {
  1280  				tx := *exportTx
  1281  				tx.Ins = []EVMInput{
  1282  					{
  1283  						Address: testEthAddrs[0],
  1284  						Amount:  1,
  1285  						AssetID: nonExistentID,
  1286  						Nonce:   0,
  1287  					},
  1288  				}
  1289  				return &tx
  1290  			},
  1291  			ctx:         ctx,
  1292  			rules:       apricotRulesPhase6,
  1293  			expectedErr: "",
  1294  		},
  1295  		"non-AVAX output Apricot Phase 6": {
  1296  			generate: func(t *testing.T) UnsignedAtomicTx {
  1297  				tx := *exportTx
  1298  				tx.ExportedOutputs = []*avax.TransferableOutput{
  1299  					{
  1300  						Asset: avax.Asset{ID: nonExistentID},
  1301  						Out: &secp256k1fx.TransferOutput{
  1302  							Amt: exportAmount,
  1303  							OutputOwners: secp256k1fx.OutputOwners{
  1304  								Locktime:  0,
  1305  								Threshold: 1,
  1306  								Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1307  							},
  1308  						},
  1309  					},
  1310  				}
  1311  				return &tx
  1312  			},
  1313  			ctx:         ctx,
  1314  			rules:       apricotRulesPhase6,
  1315  			expectedErr: "",
  1316  		},
  1317  		"non-AVAX input Banff": {
  1318  			generate: func(t *testing.T) UnsignedAtomicTx {
  1319  				tx := *exportTx
  1320  				tx.Ins = []EVMInput{
  1321  					{
  1322  						Address: testEthAddrs[0],
  1323  						Amount:  1,
  1324  						AssetID: nonExistentID,
  1325  						Nonce:   0,
  1326  					},
  1327  				}
  1328  				return &tx
  1329  			},
  1330  			ctx:         ctx,
  1331  			rules:       banffRules,
  1332  			expectedErr: errExportNonAVAXInputBanff.Error(),
  1333  		},
  1334  		"non-AVAX output Banff": {
  1335  			generate: func(t *testing.T) UnsignedAtomicTx {
  1336  				tx := *exportTx
  1337  				tx.ExportedOutputs = []*avax.TransferableOutput{
  1338  					{
  1339  						Asset: avax.Asset{ID: nonExistentID},
  1340  						Out: &secp256k1fx.TransferOutput{
  1341  							Amt: exportAmount,
  1342  							OutputOwners: secp256k1fx.OutputOwners{
  1343  								Locktime:  0,
  1344  								Threshold: 1,
  1345  								Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1346  							},
  1347  						},
  1348  					},
  1349  				}
  1350  				return &tx
  1351  			},
  1352  			ctx:         ctx,
  1353  			rules:       banffRules,
  1354  			expectedErr: errExportNonAVAXOutputBanff.Error(),
  1355  		},
  1356  	}
  1357  
  1358  	for name, test := range tests {
  1359  		t.Run(name, func(t *testing.T) {
  1360  			executeTxVerifyTest(t, test)
  1361  		})
  1362  	}
  1363  }
  1364  
  1365  // Note: this is a brittle test to ensure that the gas cost of a transaction does
  1366  // not change
  1367  func TestExportTxGasCost(t *testing.T) {
  1368  	avaxAssetID := ids.GenerateTestID()
  1369  	chainID := ids.GenerateTestID()
  1370  	xChainID := ids.GenerateTestID()
  1371  	networkID := uint32(5)
  1372  	exportAmount := uint64(5000000)
  1373  
  1374  	tests := map[string]struct {
  1375  		UnsignedExportTx *UnsignedExportTx
  1376  		Keys             [][]*crypto.PrivateKeySECP256K1R
  1377  
  1378  		BaseFee         *big.Int
  1379  		ExpectedGasUsed uint64
  1380  		ExpectedFee     uint64
  1381  		FixedFee        bool
  1382  	}{
  1383  		"simple export 1wei BaseFee": {
  1384  			UnsignedExportTx: &UnsignedExportTx{
  1385  				NetworkID:        networkID,
  1386  				BlockchainID:     chainID,
  1387  				DestinationChain: xChainID,
  1388  				Ins: []EVMInput{
  1389  					{
  1390  						Address: testEthAddrs[0],
  1391  						Amount:  exportAmount,
  1392  						AssetID: avaxAssetID,
  1393  						Nonce:   0,
  1394  					},
  1395  				},
  1396  				ExportedOutputs: []*avax.TransferableOutput{
  1397  					{
  1398  						Asset: avax.Asset{ID: avaxAssetID},
  1399  						Out: &secp256k1fx.TransferOutput{
  1400  							Amt: exportAmount,
  1401  							OutputOwners: secp256k1fx.OutputOwners{
  1402  								Locktime:  0,
  1403  								Threshold: 1,
  1404  								Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1405  							},
  1406  						},
  1407  					},
  1408  				},
  1409  			},
  1410  			Keys:            [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}},
  1411  			ExpectedGasUsed: 1230,
  1412  			ExpectedFee:     1,
  1413  			BaseFee:         big.NewInt(1),
  1414  		},
  1415  		"simple export 1wei BaseFee + fixed fee": {
  1416  			UnsignedExportTx: &UnsignedExportTx{
  1417  				NetworkID:        networkID,
  1418  				BlockchainID:     chainID,
  1419  				DestinationChain: xChainID,
  1420  				Ins: []EVMInput{
  1421  					{
  1422  						Address: testEthAddrs[0],
  1423  						Amount:  exportAmount,
  1424  						AssetID: avaxAssetID,
  1425  						Nonce:   0,
  1426  					},
  1427  				},
  1428  				ExportedOutputs: []*avax.TransferableOutput{
  1429  					{
  1430  						Asset: avax.Asset{ID: avaxAssetID},
  1431  						Out: &secp256k1fx.TransferOutput{
  1432  							Amt: exportAmount,
  1433  							OutputOwners: secp256k1fx.OutputOwners{
  1434  								Locktime:  0,
  1435  								Threshold: 1,
  1436  								Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1437  							},
  1438  						},
  1439  					},
  1440  				},
  1441  			},
  1442  			Keys:            [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}},
  1443  			ExpectedGasUsed: 11230,
  1444  			ExpectedFee:     1,
  1445  			BaseFee:         big.NewInt(1),
  1446  			FixedFee:        true,
  1447  		},
  1448  		"simple export 25Gwei BaseFee": {
  1449  			UnsignedExportTx: &UnsignedExportTx{
  1450  				NetworkID:        networkID,
  1451  				BlockchainID:     chainID,
  1452  				DestinationChain: xChainID,
  1453  				Ins: []EVMInput{
  1454  					{
  1455  						Address: testEthAddrs[0],
  1456  						Amount:  exportAmount,
  1457  						AssetID: avaxAssetID,
  1458  						Nonce:   0,
  1459  					},
  1460  				},
  1461  				ExportedOutputs: []*avax.TransferableOutput{
  1462  					{
  1463  						Asset: avax.Asset{ID: avaxAssetID},
  1464  						Out: &secp256k1fx.TransferOutput{
  1465  							Amt: exportAmount,
  1466  							OutputOwners: secp256k1fx.OutputOwners{
  1467  								Locktime:  0,
  1468  								Threshold: 1,
  1469  								Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1470  							},
  1471  						},
  1472  					},
  1473  				},
  1474  			},
  1475  			Keys:            [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}},
  1476  			ExpectedGasUsed: 1230,
  1477  			ExpectedFee:     30750,
  1478  			BaseFee:         big.NewInt(25 * params.GWei),
  1479  		},
  1480  		"simple export 225Gwei BaseFee": {
  1481  			UnsignedExportTx: &UnsignedExportTx{
  1482  				NetworkID:        networkID,
  1483  				BlockchainID:     chainID,
  1484  				DestinationChain: xChainID,
  1485  				Ins: []EVMInput{
  1486  					{
  1487  						Address: testEthAddrs[0],
  1488  						Amount:  exportAmount,
  1489  						AssetID: avaxAssetID,
  1490  						Nonce:   0,
  1491  					},
  1492  				},
  1493  				ExportedOutputs: []*avax.TransferableOutput{
  1494  					{
  1495  						Asset: avax.Asset{ID: avaxAssetID},
  1496  						Out: &secp256k1fx.TransferOutput{
  1497  							Amt: exportAmount,
  1498  							OutputOwners: secp256k1fx.OutputOwners{
  1499  								Locktime:  0,
  1500  								Threshold: 1,
  1501  								Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1502  							},
  1503  						},
  1504  					},
  1505  				},
  1506  			},
  1507  			Keys:            [][]*crypto.PrivateKeySECP256K1R{{testKeys[0]}},
  1508  			ExpectedGasUsed: 1230,
  1509  			ExpectedFee:     276750,
  1510  			BaseFee:         big.NewInt(225 * params.GWei),
  1511  		},
  1512  		"complex export 25Gwei BaseFee": {
  1513  			UnsignedExportTx: &UnsignedExportTx{
  1514  				NetworkID:        networkID,
  1515  				BlockchainID:     chainID,
  1516  				DestinationChain: xChainID,
  1517  				Ins: []EVMInput{
  1518  					{
  1519  						Address: testEthAddrs[0],
  1520  						Amount:  exportAmount,
  1521  						AssetID: avaxAssetID,
  1522  						Nonce:   0,
  1523  					},
  1524  					{
  1525  						Address: testEthAddrs[1],
  1526  						Amount:  exportAmount,
  1527  						AssetID: avaxAssetID,
  1528  						Nonce:   0,
  1529  					},
  1530  					{
  1531  						Address: testEthAddrs[2],
  1532  						Amount:  exportAmount,
  1533  						AssetID: avaxAssetID,
  1534  						Nonce:   0,
  1535  					},
  1536  				},
  1537  				ExportedOutputs: []*avax.TransferableOutput{
  1538  					{
  1539  						Asset: avax.Asset{ID: avaxAssetID},
  1540  						Out: &secp256k1fx.TransferOutput{
  1541  							Amt: exportAmount * 3,
  1542  							OutputOwners: secp256k1fx.OutputOwners{
  1543  								Locktime:  0,
  1544  								Threshold: 1,
  1545  								Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1546  							},
  1547  						},
  1548  					},
  1549  				},
  1550  			},
  1551  			Keys:            [][]*crypto.PrivateKeySECP256K1R{{testKeys[0], testKeys[0], testKeys[0]}},
  1552  			ExpectedGasUsed: 3366,
  1553  			ExpectedFee:     84150,
  1554  			BaseFee:         big.NewInt(25 * params.GWei),
  1555  		},
  1556  		"complex export 225Gwei BaseFee": {
  1557  			UnsignedExportTx: &UnsignedExportTx{
  1558  				NetworkID:        networkID,
  1559  				BlockchainID:     chainID,
  1560  				DestinationChain: xChainID,
  1561  				Ins: []EVMInput{
  1562  					{
  1563  						Address: testEthAddrs[0],
  1564  						Amount:  exportAmount,
  1565  						AssetID: avaxAssetID,
  1566  						Nonce:   0,
  1567  					},
  1568  					{
  1569  						Address: testEthAddrs[1],
  1570  						Amount:  exportAmount,
  1571  						AssetID: avaxAssetID,
  1572  						Nonce:   0,
  1573  					},
  1574  					{
  1575  						Address: testEthAddrs[2],
  1576  						Amount:  exportAmount,
  1577  						AssetID: avaxAssetID,
  1578  						Nonce:   0,
  1579  					},
  1580  				},
  1581  				ExportedOutputs: []*avax.TransferableOutput{
  1582  					{
  1583  						Asset: avax.Asset{ID: avaxAssetID},
  1584  						Out: &secp256k1fx.TransferOutput{
  1585  							Amt: exportAmount * 3,
  1586  							OutputOwners: secp256k1fx.OutputOwners{
  1587  								Locktime:  0,
  1588  								Threshold: 1,
  1589  								Addrs:     []ids.ShortID{testShortIDAddrs[0]},
  1590  							},
  1591  						},
  1592  					},
  1593  				},
  1594  			},
  1595  			Keys:            [][]*crypto.PrivateKeySECP256K1R{{testKeys[0], testKeys[0], testKeys[0]}},
  1596  			ExpectedGasUsed: 3366,
  1597  			ExpectedFee:     757350,
  1598  			BaseFee:         big.NewInt(225 * params.GWei),
  1599  		},
  1600  	}
  1601  
  1602  	for name, test := range tests {
  1603  		t.Run(name, func(t *testing.T) {
  1604  			tx := &Tx{UnsignedAtomicTx: test.UnsignedExportTx}
  1605  
  1606  			// Sign with the correct key
  1607  			if err := tx.Sign(Codec, test.Keys); err != nil {
  1608  				t.Fatal(err)
  1609  			}
  1610  
  1611  			gasUsed, err := tx.GasUsed(test.FixedFee)
  1612  			if err != nil {
  1613  				t.Fatal(err)
  1614  			}
  1615  			if gasUsed != test.ExpectedGasUsed {
  1616  				t.Fatalf("Expected gasUsed to be %d, but found %d", test.ExpectedGasUsed, gasUsed)
  1617  			}
  1618  
  1619  			fee, err := calculateDynamicFee(gasUsed, test.BaseFee)
  1620  			if err != nil {
  1621  				t.Fatal(err)
  1622  			}
  1623  			if fee != test.ExpectedFee {
  1624  				t.Fatalf("Expected fee to be %d, but found %d", test.ExpectedFee, fee)
  1625  			}
  1626  		})
  1627  	}
  1628  }
  1629  
  1630  func TestNewExportTx(t *testing.T) {
  1631  	tests := []struct {
  1632  		name               string
  1633  		genesis            string
  1634  		rules              params.Rules
  1635  		bal                uint64
  1636  		expectedBurnedAVAX uint64
  1637  	}{
  1638  		{
  1639  			name:               "apricot phase 0",
  1640  			genesis:            genesisJSONApricotPhase0,
  1641  			rules:              apricotRulesPhase0,
  1642  			bal:                44000000,
  1643  			expectedBurnedAVAX: 1000000,
  1644  		},
  1645  		{
  1646  			name:               "apricot phase 1",
  1647  			genesis:            genesisJSONApricotPhase1,
  1648  			rules:              apricotRulesPhase1,
  1649  			bal:                44000000,
  1650  			expectedBurnedAVAX: 1000000,
  1651  		},
  1652  		{
  1653  			name:               "apricot phase 2",
  1654  			genesis:            genesisJSONApricotPhase2,
  1655  			rules:              apricotRulesPhase2,
  1656  			bal:                43000000,
  1657  			expectedBurnedAVAX: 1000000,
  1658  		},
  1659  		{
  1660  			name:               "apricot phase 3",
  1661  			genesis:            genesisJSONApricotPhase3,
  1662  			rules:              apricotRulesPhase3,
  1663  			bal:                44446500,
  1664  			expectedBurnedAVAX: 276750,
  1665  		},
  1666  		{
  1667  			name:               "apricot phase 4",
  1668  			genesis:            genesisJSONApricotPhase4,
  1669  			rules:              apricotRulesPhase4,
  1670  			bal:                44446500,
  1671  			expectedBurnedAVAX: 276750,
  1672  		},
  1673  		{
  1674  			name:               "apricot phase 5",
  1675  			genesis:            genesisJSONApricotPhase5,
  1676  			rules:              apricotRulesPhase5,
  1677  			bal:                39946500,
  1678  			expectedBurnedAVAX: 2526750,
  1679  		},
  1680  	}
  1681  	for _, test := range tests {
  1682  		t.Run(test.name, func(t *testing.T) {
  1683  			issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, test.genesis, "", "")
  1684  
  1685  			defer func() {
  1686  				if err := vm.Shutdown(); err != nil {
  1687  					t.Fatal(err)
  1688  				}
  1689  			}()
  1690  
  1691  			parent := vm.LastAcceptedBlockInternal().(*Block)
  1692  			importAmount := uint64(50000000)
  1693  			utxoID := avax.UTXOID{TxID: ids.GenerateTestID()}
  1694  
  1695  			utxo := &avax.UTXO{
  1696  				UTXOID: utxoID,
  1697  				Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
  1698  				Out: &secp256k1fx.TransferOutput{
  1699  					Amt: importAmount,
  1700  					OutputOwners: secp256k1fx.OutputOwners{
  1701  						Threshold: 1,
  1702  						Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
  1703  					},
  1704  				},
  1705  			}
  1706  			utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
  1707  			if err != nil {
  1708  				t.Fatal(err)
  1709  			}
  1710  
  1711  			xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
  1712  			inputID := utxo.InputID()
  1713  			if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{
  1714  				Key:   inputID[:],
  1715  				Value: utxoBytes,
  1716  				Traits: [][]byte{
  1717  					testKeys[0].PublicKey().Address().Bytes(),
  1718  				},
  1719  			}}}}); err != nil {
  1720  				t.Fatal(err)
  1721  			}
  1722  
  1723  			tx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1724  			if err != nil {
  1725  				t.Fatal(err)
  1726  			}
  1727  
  1728  			if err := vm.issueTx(tx, true /*=local*/); err != nil {
  1729  				t.Fatal(err)
  1730  			}
  1731  
  1732  			<-issuer
  1733  
  1734  			blk, err := vm.BuildBlock()
  1735  			if err != nil {
  1736  				t.Fatal(err)
  1737  			}
  1738  
  1739  			if err := blk.Verify(); err != nil {
  1740  				t.Fatal(err)
  1741  			}
  1742  
  1743  			if err := vm.SetPreference(blk.ID()); err != nil {
  1744  				t.Fatal(err)
  1745  			}
  1746  
  1747  			if err := blk.Accept(); err != nil {
  1748  				t.Fatal(err)
  1749  			}
  1750  
  1751  			parent = vm.LastAcceptedBlockInternal().(*Block)
  1752  			exportAmount := uint64(5000000)
  1753  
  1754  			tx, err = vm.newExportTx(vm.ctx.AVAXAssetID, exportAmount, vm.ctx.XChainID, testShortIDAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1755  			if err != nil {
  1756  				t.Fatal(err)
  1757  			}
  1758  
  1759  			exportTx := tx.UnsignedAtomicTx
  1760  
  1761  			if err := exportTx.SemanticVerify(vm, tx, parent, parent.ethBlock.BaseFee(), test.rules); err != nil {
  1762  				t.Fatal("newExportTx created an invalid transaction", err)
  1763  			}
  1764  
  1765  			burnedAVAX, err := exportTx.Burned(vm.ctx.AVAXAssetID)
  1766  			if err != nil {
  1767  				t.Fatal(err)
  1768  			}
  1769  			if burnedAVAX != test.expectedBurnedAVAX {
  1770  				t.Fatalf("burned wrong amount of AVAX - expected %d burned %d", test.expectedBurnedAVAX, burnedAVAX)
  1771  			}
  1772  
  1773  			commitBatch, err := vm.db.CommitBatch()
  1774  			if err != nil {
  1775  				t.Fatalf("Failed to create commit batch for VM due to %s", err)
  1776  			}
  1777  			chainID, atomicRequests, err := exportTx.AtomicOps()
  1778  
  1779  			if err != nil {
  1780  				t.Fatalf("Failed to accept export transaction due to: %s", err)
  1781  			}
  1782  
  1783  			if err := vm.ctx.SharedMemory.Apply(map[ids.ID]*atomic.Requests{chainID: {PutRequests: atomicRequests.PutRequests}}, commitBatch); err != nil {
  1784  				t.Fatal(err)
  1785  			}
  1786  
  1787  			sdb, err := vm.blockChain.State()
  1788  			if err != nil {
  1789  				t.Fatal(err)
  1790  			}
  1791  			err = exportTx.EVMStateTransfer(vm.ctx, sdb)
  1792  			if err != nil {
  1793  				t.Fatal(err)
  1794  			}
  1795  
  1796  			addr := GetEthAddress(testKeys[0])
  1797  			if sdb.GetBalance(addr).Cmp(new(big.Int).SetUint64(test.bal*units.Avax)) != 0 {
  1798  				t.Fatalf("address balance %s equal %s not %s", addr.String(), sdb.GetBalance(addr), new(big.Int).SetUint64(test.bal*units.Avax))
  1799  			}
  1800  		})
  1801  	}
  1802  }
  1803  
  1804  func TestNewExportTxMulticoin(t *testing.T) {
  1805  	tests := []struct {
  1806  		name    string
  1807  		genesis string
  1808  		rules   params.Rules
  1809  		bal     uint64
  1810  		balmc   uint64
  1811  	}{
  1812  		{
  1813  			name:    "apricot phase 0",
  1814  			genesis: genesisJSONApricotPhase0,
  1815  			rules:   apricotRulesPhase0,
  1816  			bal:     49000000,
  1817  			balmc:   25000000,
  1818  		},
  1819  		{
  1820  			name:    "apricot phase 1",
  1821  			genesis: genesisJSONApricotPhase1,
  1822  			rules:   apricotRulesPhase1,
  1823  			bal:     49000000,
  1824  			balmc:   25000000,
  1825  		},
  1826  		{
  1827  			name:    "apricot phase 2",
  1828  			genesis: genesisJSONApricotPhase2,
  1829  			rules:   apricotRulesPhase2,
  1830  			bal:     48000000,
  1831  			balmc:   25000000,
  1832  		},
  1833  		{
  1834  			name:    "apricot phase 3",
  1835  			genesis: genesisJSONApricotPhase3,
  1836  			rules:   apricotRulesPhase3,
  1837  			bal:     48947900,
  1838  			balmc:   25000000,
  1839  		},
  1840  	}
  1841  	for _, test := range tests {
  1842  		t.Run(test.name, func(t *testing.T) {
  1843  			issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, test.genesis, "", "")
  1844  
  1845  			defer func() {
  1846  				if err := vm.Shutdown(); err != nil {
  1847  					t.Fatal(err)
  1848  				}
  1849  			}()
  1850  
  1851  			parent := vm.LastAcceptedBlockInternal().(*Block)
  1852  			importAmount := uint64(50000000)
  1853  			utxoID := avax.UTXOID{TxID: ids.GenerateTestID()}
  1854  
  1855  			utxo := &avax.UTXO{
  1856  				UTXOID: utxoID,
  1857  				Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
  1858  				Out: &secp256k1fx.TransferOutput{
  1859  					Amt: importAmount,
  1860  					OutputOwners: secp256k1fx.OutputOwners{
  1861  						Threshold: 1,
  1862  						Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
  1863  					},
  1864  				},
  1865  			}
  1866  			utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
  1867  			if err != nil {
  1868  				t.Fatal(err)
  1869  			}
  1870  
  1871  			inputID := utxo.InputID()
  1872  
  1873  			tid := ids.GenerateTestID()
  1874  			importAmount2 := uint64(30000000)
  1875  			utxoID2 := avax.UTXOID{TxID: ids.GenerateTestID()}
  1876  			utxo2 := &avax.UTXO{
  1877  				UTXOID: utxoID2,
  1878  				Asset:  avax.Asset{ID: tid},
  1879  				Out: &secp256k1fx.TransferOutput{
  1880  					Amt: importAmount2,
  1881  					OutputOwners: secp256k1fx.OutputOwners{
  1882  						Threshold: 1,
  1883  						Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
  1884  					},
  1885  				},
  1886  			}
  1887  			utxoBytes2, err := vm.codec.Marshal(codecVersion, utxo2)
  1888  			if err != nil {
  1889  				t.Fatal(err)
  1890  			}
  1891  
  1892  			xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
  1893  			inputID2 := utxo2.InputID()
  1894  			if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{
  1895  				{
  1896  					Key:   inputID[:],
  1897  					Value: utxoBytes,
  1898  					Traits: [][]byte{
  1899  						testKeys[0].PublicKey().Address().Bytes(),
  1900  					},
  1901  				},
  1902  				{
  1903  					Key:   inputID2[:],
  1904  					Value: utxoBytes2,
  1905  					Traits: [][]byte{
  1906  						testKeys[0].PublicKey().Address().Bytes(),
  1907  					},
  1908  				},
  1909  			}}}); err != nil {
  1910  				t.Fatal(err)
  1911  			}
  1912  
  1913  			tx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1914  			if err != nil {
  1915  				t.Fatal(err)
  1916  			}
  1917  
  1918  			if err := vm.issueTx(tx, false); err != nil {
  1919  				t.Fatal(err)
  1920  			}
  1921  
  1922  			<-issuer
  1923  
  1924  			blk, err := vm.BuildBlock()
  1925  			if err != nil {
  1926  				t.Fatal(err)
  1927  			}
  1928  
  1929  			if err := blk.Verify(); err != nil {
  1930  				t.Fatal(err)
  1931  			}
  1932  
  1933  			if err := vm.SetPreference(blk.ID()); err != nil {
  1934  				t.Fatal(err)
  1935  			}
  1936  
  1937  			if err := blk.Accept(); err != nil {
  1938  				t.Fatal(err)
  1939  			}
  1940  
  1941  			parent = vm.LastAcceptedBlockInternal().(*Block)
  1942  			exportAmount := uint64(5000000)
  1943  
  1944  			testKeys0Addr := GetEthAddress(testKeys[0])
  1945  			exportId, err := ids.ToShortID(testKeys0Addr[:])
  1946  			if err != nil {
  1947  				t.Fatal(err)
  1948  			}
  1949  
  1950  			tx, err = vm.newExportTx(tid, exportAmount, vm.ctx.XChainID, exportId, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1951  			if err != nil {
  1952  				t.Fatal(err)
  1953  			}
  1954  
  1955  			exportTx := tx.UnsignedAtomicTx
  1956  
  1957  			if err := exportTx.SemanticVerify(vm, tx, parent, parent.ethBlock.BaseFee(), test.rules); err != nil {
  1958  				t.Fatal("newExportTx created an invalid transaction", err)
  1959  			}
  1960  
  1961  			commitBatch, err := vm.db.CommitBatch()
  1962  			if err != nil {
  1963  				t.Fatalf("Failed to create commit batch for VM due to %s", err)
  1964  			}
  1965  			chainID, atomicRequests, err := exportTx.AtomicOps()
  1966  
  1967  			if err != nil {
  1968  				t.Fatalf("Failed to accept export transaction due to: %s", err)
  1969  			}
  1970  
  1971  			if err := vm.ctx.SharedMemory.Apply(map[ids.ID]*atomic.Requests{chainID: {PutRequests: atomicRequests.PutRequests}}, commitBatch); err != nil {
  1972  				t.Fatal(err)
  1973  			}
  1974  
  1975  			stdb, err := vm.blockChain.State()
  1976  			if err != nil {
  1977  				t.Fatal(err)
  1978  			}
  1979  			err = exportTx.EVMStateTransfer(vm.ctx, stdb)
  1980  			if err != nil {
  1981  				t.Fatal(err)
  1982  			}
  1983  
  1984  			addr := GetEthAddress(testKeys[0])
  1985  			if stdb.GetBalance(addr).Cmp(new(big.Int).SetUint64(test.bal*units.Avax)) != 0 {
  1986  				t.Fatalf("address balance %s equal %s not %s", addr.String(), stdb.GetBalance(addr), new(big.Int).SetUint64(test.bal*units.Avax))
  1987  			}
  1988  			if stdb.GetBalanceMultiCoin(addr, common.BytesToHash(tid[:])).Cmp(new(big.Int).SetUint64(test.balmc)) != 0 {
  1989  				t.Fatalf("address balance multicoin %s equal %s not %s", addr.String(), stdb.GetBalanceMultiCoin(addr, common.BytesToHash(tid[:])), new(big.Int).SetUint64(test.balmc))
  1990  			}
  1991  		})
  1992  	}
  1993  }