github.com/MetalBlockchain/metalgo@v1.11.9/vms/avm/vm_test.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package avm
     5  
     6  import (
     7  	"context"
     8  	"math"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/MetalBlockchain/metalgo/chains/atomic"
    14  	"github.com/MetalBlockchain/metalgo/codec"
    15  	"github.com/MetalBlockchain/metalgo/database"
    16  	"github.com/MetalBlockchain/metalgo/database/memdb"
    17  	"github.com/MetalBlockchain/metalgo/ids"
    18  	"github.com/MetalBlockchain/metalgo/snow/engine/common"
    19  	"github.com/MetalBlockchain/metalgo/snow/snowtest"
    20  	"github.com/MetalBlockchain/metalgo/utils/constants"
    21  	"github.com/MetalBlockchain/metalgo/utils/crypto/secp256k1"
    22  	"github.com/MetalBlockchain/metalgo/vms/avm/txs"
    23  	"github.com/MetalBlockchain/metalgo/vms/components/avax"
    24  	"github.com/MetalBlockchain/metalgo/vms/components/verify"
    25  	"github.com/MetalBlockchain/metalgo/vms/nftfx"
    26  	"github.com/MetalBlockchain/metalgo/vms/propertyfx"
    27  	"github.com/MetalBlockchain/metalgo/vms/secp256k1fx"
    28  )
    29  
    30  func TestInvalidGenesis(t *testing.T) {
    31  	require := require.New(t)
    32  
    33  	vm := &VM{}
    34  	ctx := snowtest.Context(t, snowtest.XChainID)
    35  	ctx.Lock.Lock()
    36  	defer ctx.Lock.Unlock()
    37  
    38  	err := vm.Initialize(
    39  		context.Background(),
    40  		ctx,                          // context
    41  		memdb.New(),                  // database
    42  		nil,                          // genesisState
    43  		nil,                          // upgradeBytes
    44  		nil,                          // configBytes
    45  		make(chan common.Message, 1), // engineMessenger
    46  		nil,                          // fxs
    47  		nil,                          // AppSender
    48  	)
    49  	require.ErrorIs(err, codec.ErrCantUnpackVersion)
    50  }
    51  
    52  func TestInvalidFx(t *testing.T) {
    53  	require := require.New(t)
    54  
    55  	vm := &VM{}
    56  	ctx := snowtest.Context(t, snowtest.XChainID)
    57  	ctx.Lock.Lock()
    58  	defer func() {
    59  		require.NoError(vm.Shutdown(context.Background()))
    60  		ctx.Lock.Unlock()
    61  	}()
    62  
    63  	genesisBytes := buildGenesisTest(t)
    64  	err := vm.Initialize(
    65  		context.Background(),
    66  		ctx,                          // context
    67  		memdb.New(),                  // database
    68  		genesisBytes,                 // genesisState
    69  		nil,                          // upgradeBytes
    70  		nil,                          // configBytes
    71  		make(chan common.Message, 1), // engineMessenger
    72  		[]*common.Fx{ // fxs
    73  			nil,
    74  		},
    75  		nil,
    76  	)
    77  	require.ErrorIs(err, errIncompatibleFx)
    78  }
    79  
    80  func TestFxInitializationFailure(t *testing.T) {
    81  	require := require.New(t)
    82  
    83  	vm := &VM{}
    84  	ctx := snowtest.Context(t, snowtest.XChainID)
    85  	ctx.Lock.Lock()
    86  	defer func() {
    87  		require.NoError(vm.Shutdown(context.Background()))
    88  		ctx.Lock.Unlock()
    89  	}()
    90  
    91  	genesisBytes := buildGenesisTest(t)
    92  	err := vm.Initialize(
    93  		context.Background(),
    94  		ctx,                          // context
    95  		memdb.New(),                  // database
    96  		genesisBytes,                 // genesisState
    97  		nil,                          // upgradeBytes
    98  		nil,                          // configBytes
    99  		make(chan common.Message, 1), // engineMessenger
   100  		[]*common.Fx{{ // fxs
   101  			ID: ids.Empty,
   102  			Fx: &FxTest{
   103  				InitializeF: func(interface{}) error {
   104  					return errUnknownFx
   105  				},
   106  			},
   107  		}},
   108  		nil,
   109  	)
   110  	require.ErrorIs(err, errUnknownFx)
   111  }
   112  
   113  func TestIssueTx(t *testing.T) {
   114  	require := require.New(t)
   115  
   116  	env := setup(t, &envConfig{
   117  		fork: latest,
   118  	})
   119  	env.vm.ctx.Lock.Unlock()
   120  
   121  	tx := newTx(t, env.genesisBytes, env.vm.ctx.ChainID, env.vm.parser, "AVAX")
   122  	issueAndAccept(require, env.vm, env.issuer, tx)
   123  }
   124  
   125  // Test issuing a transaction that creates an NFT family
   126  func TestIssueNFT(t *testing.T) {
   127  	require := require.New(t)
   128  
   129  	env := setup(t, &envConfig{
   130  		fork: latest,
   131  	})
   132  	env.vm.ctx.Lock.Unlock()
   133  
   134  	var (
   135  		key = keys[0]
   136  		kc  = secp256k1fx.NewKeychain(key)
   137  	)
   138  
   139  	// Create the asset
   140  	initialStates := map[uint32][]verify.State{
   141  		1: {
   142  			&nftfx.MintOutput{
   143  				GroupID: 1,
   144  				OutputOwners: secp256k1fx.OutputOwners{
   145  					Threshold: 1,
   146  					Addrs:     []ids.ShortID{key.PublicKey().Address()},
   147  				},
   148  			},
   149  		},
   150  	}
   151  
   152  	createAssetTx, err := env.txBuilder.CreateAssetTx(
   153  		"Team Rocket", // name
   154  		"TR",          // symbol
   155  		0,             // denomination
   156  		initialStates,
   157  		kc,
   158  		key.Address(),
   159  	)
   160  	require.NoError(err)
   161  	issueAndAccept(require, env.vm, env.issuer, createAssetTx)
   162  
   163  	// Mint the NFT
   164  	mintNFTTx, err := env.txBuilder.MintNFT(
   165  		createAssetTx.ID(),
   166  		[]byte{'h', 'e', 'l', 'l', 'o'}, // payload
   167  		[]*secp256k1fx.OutputOwners{{
   168  			Threshold: 1,
   169  			Addrs:     []ids.ShortID{key.Address()},
   170  		}},
   171  		kc,
   172  		key.Address(),
   173  	)
   174  	require.NoError(err)
   175  	issueAndAccept(require, env.vm, env.issuer, mintNFTTx)
   176  
   177  	// Move the NFT
   178  	utxos, err := avax.GetAllUTXOs(env.vm.state, kc.Addresses())
   179  	require.NoError(err)
   180  	transferOp, _, err := env.vm.SpendNFT(
   181  		utxos,
   182  		kc,
   183  		createAssetTx.ID(),
   184  		1,
   185  		keys[2].Address(),
   186  	)
   187  	require.NoError(err)
   188  
   189  	transferNFTTx, err := env.txBuilder.Operation(
   190  		transferOp,
   191  		kc,
   192  		key.Address(),
   193  	)
   194  	require.NoError(err)
   195  	issueAndAccept(require, env.vm, env.issuer, transferNFTTx)
   196  }
   197  
   198  // Test issuing a transaction that creates an Property family
   199  func TestIssueProperty(t *testing.T) {
   200  	require := require.New(t)
   201  
   202  	env := setup(t, &envConfig{
   203  		fork: latest,
   204  		additionalFxs: []*common.Fx{{
   205  			ID: propertyfx.ID,
   206  			Fx: &propertyfx.Fx{},
   207  		}},
   208  	})
   209  	env.vm.ctx.Lock.Unlock()
   210  
   211  	var (
   212  		key = keys[0]
   213  		kc  = secp256k1fx.NewKeychain(key)
   214  	)
   215  
   216  	// create the asset
   217  	initialStates := map[uint32][]verify.State{
   218  		2: {
   219  			&propertyfx.MintOutput{
   220  				OutputOwners: secp256k1fx.OutputOwners{
   221  					Threshold: 1,
   222  					Addrs:     []ids.ShortID{keys[0].PublicKey().Address()},
   223  				},
   224  			},
   225  		},
   226  	}
   227  
   228  	createAssetTx, err := env.txBuilder.CreateAssetTx(
   229  		"Team Rocket", // name
   230  		"TR",          // symbol
   231  		0,             // denomination
   232  		initialStates,
   233  		kc,
   234  		key.Address(),
   235  	)
   236  	require.NoError(err)
   237  	issueAndAccept(require, env.vm, env.issuer, createAssetTx)
   238  
   239  	// mint the property
   240  	mintPropertyOp := &txs.Operation{
   241  		Asset: avax.Asset{ID: createAssetTx.ID()},
   242  		UTXOIDs: []*avax.UTXOID{{
   243  			TxID:        createAssetTx.ID(),
   244  			OutputIndex: 1,
   245  		}},
   246  		Op: &propertyfx.MintOperation{
   247  			MintInput: secp256k1fx.Input{
   248  				SigIndices: []uint32{0},
   249  			},
   250  			MintOutput: propertyfx.MintOutput{
   251  				OutputOwners: secp256k1fx.OutputOwners{
   252  					Threshold: 1,
   253  					Addrs:     []ids.ShortID{keys[0].PublicKey().Address()},
   254  				},
   255  			},
   256  			OwnedOutput: propertyfx.OwnedOutput{},
   257  		},
   258  	}
   259  
   260  	mintPropertyTx, err := env.txBuilder.Operation(
   261  		[]*txs.Operation{mintPropertyOp},
   262  		kc,
   263  		key.Address(),
   264  	)
   265  	require.NoError(err)
   266  	issueAndAccept(require, env.vm, env.issuer, mintPropertyTx)
   267  
   268  	// burn the property
   269  	burnPropertyOp := &txs.Operation{
   270  		Asset: avax.Asset{ID: createAssetTx.ID()},
   271  		UTXOIDs: []*avax.UTXOID{{
   272  			TxID:        mintPropertyTx.ID(),
   273  			OutputIndex: 2,
   274  		}},
   275  		Op: &propertyfx.BurnOperation{Input: secp256k1fx.Input{}},
   276  	}
   277  
   278  	burnPropertyTx, err := env.txBuilder.Operation(
   279  		[]*txs.Operation{burnPropertyOp},
   280  		kc,
   281  		key.Address(),
   282  	)
   283  	require.NoError(err)
   284  	issueAndAccept(require, env.vm, env.issuer, burnPropertyTx)
   285  }
   286  
   287  func TestIssueTxWithFeeAsset(t *testing.T) {
   288  	require := require.New(t)
   289  
   290  	env := setup(t, &envConfig{
   291  		fork:             latest,
   292  		isCustomFeeAsset: true,
   293  	})
   294  	env.vm.ctx.Lock.Unlock()
   295  
   296  	// send first asset
   297  	tx := newTx(t, env.genesisBytes, env.vm.ctx.ChainID, env.vm.parser, feeAssetName)
   298  	issueAndAccept(require, env.vm, env.issuer, tx)
   299  }
   300  
   301  func TestIssueTxWithAnotherAsset(t *testing.T) {
   302  	require := require.New(t)
   303  
   304  	env := setup(t, &envConfig{
   305  		fork:             latest,
   306  		isCustomFeeAsset: true,
   307  	})
   308  	env.vm.ctx.Lock.Unlock()
   309  
   310  	// send second asset
   311  	var (
   312  		key = keys[0]
   313  		kc  = secp256k1fx.NewKeychain(key)
   314  
   315  		feeAssetCreateTx = getCreateTxFromGenesisTest(t, env.genesisBytes, feeAssetName)
   316  		createTx         = getCreateTxFromGenesisTest(t, env.genesisBytes, otherAssetName)
   317  	)
   318  
   319  	tx, err := env.txBuilder.BaseTx(
   320  		[]*avax.TransferableOutput{
   321  			{ // fee asset
   322  				Asset: avax.Asset{ID: feeAssetCreateTx.ID()},
   323  				Out: &secp256k1fx.TransferOutput{
   324  					Amt: startBalance - env.vm.TxFee,
   325  					OutputOwners: secp256k1fx.OutputOwners{
   326  						Threshold: 1,
   327  						Addrs:     []ids.ShortID{key.PublicKey().Address()},
   328  					},
   329  				},
   330  			},
   331  			{ // issued asset
   332  				Asset: avax.Asset{ID: createTx.ID()},
   333  				Out: &secp256k1fx.TransferOutput{
   334  					Amt: startBalance - env.vm.TxFee,
   335  					OutputOwners: secp256k1fx.OutputOwners{
   336  						Threshold: 1,
   337  						Addrs:     []ids.ShortID{key.PublicKey().Address()},
   338  					},
   339  				},
   340  			},
   341  		},
   342  		nil, // memo
   343  		kc,
   344  		key.Address(),
   345  	)
   346  	require.NoError(err)
   347  	issueAndAccept(require, env.vm, env.issuer, tx)
   348  }
   349  
   350  func TestVMFormat(t *testing.T) {
   351  	env := setup(t, &envConfig{
   352  		fork: latest,
   353  	})
   354  	defer env.vm.ctx.Lock.Unlock()
   355  
   356  	tests := []struct {
   357  		in       ids.ShortID
   358  		expected string
   359  	}{
   360  		{
   361  			in:       ids.ShortEmpty,
   362  			expected: "X-testing1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtu2yas",
   363  		},
   364  	}
   365  	for _, test := range tests {
   366  		t.Run(test.in.String(), func(t *testing.T) {
   367  			require := require.New(t)
   368  			addrStr, err := env.vm.FormatLocalAddress(test.in)
   369  			require.NoError(err)
   370  			require.Equal(test.expected, addrStr)
   371  		})
   372  	}
   373  }
   374  
   375  func TestTxAcceptAfterParseTx(t *testing.T) {
   376  	require := require.New(t)
   377  
   378  	env := setup(t, &envConfig{
   379  		fork:          latest,
   380  		notLinearized: true,
   381  	})
   382  	defer env.vm.ctx.Lock.Unlock()
   383  
   384  	var (
   385  		key = keys[0]
   386  		kc  = secp256k1fx.NewKeychain(key)
   387  	)
   388  
   389  	firstTx, err := env.txBuilder.BaseTx(
   390  		[]*avax.TransferableOutput{{
   391  			Asset: avax.Asset{ID: env.genesisTx.ID()},
   392  			Out: &secp256k1fx.TransferOutput{
   393  				Amt: startBalance - env.vm.TxFee,
   394  				OutputOwners: secp256k1fx.OutputOwners{
   395  					Threshold: 1,
   396  					Addrs:     []ids.ShortID{key.PublicKey().Address()},
   397  				},
   398  			},
   399  		}},
   400  		nil, // memo
   401  		kc,
   402  		key.Address(),
   403  	)
   404  	require.NoError(err)
   405  
   406  	// let secondTx spend firstTx outputs
   407  	secondTx := &txs.Tx{Unsigned: &txs.BaseTx{
   408  		BaseTx: avax.BaseTx{
   409  			NetworkID:    constants.UnitTestID,
   410  			BlockchainID: env.vm.ctx.XChainID,
   411  			Ins: []*avax.TransferableInput{{
   412  				UTXOID: avax.UTXOID{
   413  					TxID:        firstTx.ID(),
   414  					OutputIndex: 0,
   415  				},
   416  				Asset: avax.Asset{ID: env.genesisTx.ID()},
   417  				In: &secp256k1fx.TransferInput{
   418  					Amt: startBalance - env.vm.TxFee,
   419  					Input: secp256k1fx.Input{
   420  						SigIndices: []uint32{
   421  							0,
   422  						},
   423  					},
   424  				},
   425  			}},
   426  		},
   427  	}}
   428  	require.NoError(secondTx.SignSECP256K1Fx(env.vm.parser.Codec(), [][]*secp256k1.PrivateKey{{key}}))
   429  
   430  	parsedFirstTx, err := env.vm.ParseTx(context.Background(), firstTx.Bytes())
   431  	require.NoError(err)
   432  
   433  	require.NoError(parsedFirstTx.Verify(context.Background()))
   434  	require.NoError(parsedFirstTx.Accept(context.Background()))
   435  
   436  	parsedSecondTx, err := env.vm.ParseTx(context.Background(), secondTx.Bytes())
   437  	require.NoError(err)
   438  
   439  	require.NoError(parsedSecondTx.Verify(context.Background()))
   440  	require.NoError(parsedSecondTx.Accept(context.Background()))
   441  
   442  	_, err = env.vm.state.GetTx(firstTx.ID())
   443  	require.NoError(err)
   444  
   445  	_, err = env.vm.state.GetTx(secondTx.ID())
   446  	require.NoError(err)
   447  }
   448  
   449  // Test issuing an import transaction.
   450  func TestIssueImportTx(t *testing.T) {
   451  	require := require.New(t)
   452  
   453  	env := setup(t, &envConfig{
   454  		fork: durango,
   455  	})
   456  	defer env.vm.ctx.Lock.Unlock()
   457  
   458  	peerSharedMemory := env.sharedMemory.NewSharedMemory(constants.PlatformChainID)
   459  
   460  	genesisTx := getCreateTxFromGenesisTest(t, env.genesisBytes, "AVAX")
   461  	avaxID := genesisTx.ID()
   462  
   463  	var (
   464  		key = keys[0]
   465  		kc  = secp256k1fx.NewKeychain(key)
   466  
   467  		utxoID = avax.UTXOID{
   468  			TxID: ids.ID{
   469  				0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   470  				0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   471  				0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   472  				0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   473  			},
   474  		}
   475  		txAssetID    = avax.Asset{ID: avaxID}
   476  		importedUtxo = &avax.UTXO{
   477  			UTXOID: utxoID,
   478  			Asset:  txAssetID,
   479  			Out: &secp256k1fx.TransferOutput{
   480  				Amt: 1010,
   481  				OutputOwners: secp256k1fx.OutputOwners{
   482  					Threshold: 1,
   483  					Addrs:     []ids.ShortID{key.PublicKey().Address()},
   484  				},
   485  			},
   486  		}
   487  	)
   488  
   489  	// Provide the platform UTXO:
   490  	utxoBytes, err := env.vm.parser.Codec().Marshal(txs.CodecVersion, importedUtxo)
   491  	require.NoError(err)
   492  
   493  	inputID := importedUtxo.InputID()
   494  	require.NoError(peerSharedMemory.Apply(map[ids.ID]*atomic.Requests{
   495  		env.vm.ctx.ChainID: {
   496  			PutRequests: []*atomic.Element{{
   497  				Key:   inputID[:],
   498  				Value: utxoBytes,
   499  				Traits: [][]byte{
   500  					key.PublicKey().Address().Bytes(),
   501  				},
   502  			}},
   503  		},
   504  	}))
   505  
   506  	tx, err := env.txBuilder.ImportTx(
   507  		constants.PlatformChainID, // source chain
   508  		key.Address(),
   509  		kc,
   510  	)
   511  	require.NoError(err)
   512  
   513  	env.vm.ctx.Lock.Unlock()
   514  
   515  	issueAndAccept(require, env.vm, env.issuer, tx)
   516  
   517  	env.vm.ctx.Lock.Lock()
   518  
   519  	assertIndexedTX(t, env.vm.db, 0, key.PublicKey().Address(), txAssetID.AssetID(), tx.ID())
   520  	assertLatestIdx(t, env.vm.db, key.PublicKey().Address(), avaxID, 1)
   521  
   522  	id := utxoID.InputID()
   523  	_, err = env.vm.ctx.SharedMemory.Get(constants.PlatformChainID, [][]byte{id[:]})
   524  	require.ErrorIs(err, database.ErrNotFound)
   525  }
   526  
   527  // Test force accepting an import transaction.
   528  func TestForceAcceptImportTx(t *testing.T) {
   529  	require := require.New(t)
   530  
   531  	env := setup(t, &envConfig{
   532  		fork:          durango,
   533  		notLinearized: true,
   534  	})
   535  	defer env.vm.ctx.Lock.Unlock()
   536  
   537  	genesisTx := getCreateTxFromGenesisTest(t, env.genesisBytes, "AVAX")
   538  	avaxID := genesisTx.ID()
   539  
   540  	key := keys[0]
   541  	utxoID := avax.UTXOID{
   542  		TxID: ids.ID{
   543  			0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
   544  			0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
   545  			0x0b, 0x2b, 0x4b, 0x6b, 0x8a, 0xaa, 0xca, 0xea,
   546  			0x09, 0x29, 0x49, 0x69, 0x88, 0xa8, 0xc8, 0xe8,
   547  		},
   548  	}
   549  
   550  	txAssetID := avax.Asset{ID: avaxID}
   551  	tx := &txs.Tx{Unsigned: &txs.ImportTx{
   552  		BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
   553  			NetworkID:    constants.UnitTestID,
   554  			BlockchainID: env.vm.ctx.XChainID,
   555  			Outs: []*avax.TransferableOutput{{
   556  				Asset: txAssetID,
   557  				Out: &secp256k1fx.TransferOutput{
   558  					Amt: 10,
   559  					OutputOwners: secp256k1fx.OutputOwners{
   560  						Threshold: 1,
   561  						Addrs:     []ids.ShortID{keys[0].PublicKey().Address()},
   562  					},
   563  				},
   564  			}},
   565  		}},
   566  		SourceChain: constants.PlatformChainID,
   567  		ImportedIns: []*avax.TransferableInput{{
   568  			UTXOID: utxoID,
   569  			Asset:  txAssetID,
   570  			In: &secp256k1fx.TransferInput{
   571  				Amt: 1010,
   572  				Input: secp256k1fx.Input{
   573  					SigIndices: []uint32{0},
   574  				},
   575  			},
   576  		}},
   577  	}}
   578  	require.NoError(tx.SignSECP256K1Fx(env.vm.parser.Codec(), [][]*secp256k1.PrivateKey{{key}}))
   579  
   580  	parsedTx, err := env.vm.ParseTx(context.Background(), tx.Bytes())
   581  	require.NoError(err)
   582  
   583  	require.NoError(parsedTx.Verify(context.Background()))
   584  	require.NoError(parsedTx.Accept(context.Background()))
   585  
   586  	assertIndexedTX(t, env.vm.db, 0, key.PublicKey().Address(), txAssetID.AssetID(), tx.ID())
   587  	assertLatestIdx(t, env.vm.db, key.PublicKey().Address(), avaxID, 1)
   588  
   589  	id := utxoID.InputID()
   590  	_, err = env.vm.ctx.SharedMemory.Get(constants.PlatformChainID, [][]byte{id[:]})
   591  	require.ErrorIs(err, database.ErrNotFound)
   592  }
   593  
   594  func TestImportTxNotState(t *testing.T) {
   595  	require := require.New(t)
   596  
   597  	intf := interface{}(&txs.ImportTx{})
   598  	_, ok := intf.(verify.State)
   599  	require.False(ok)
   600  }
   601  
   602  // Test issuing an export transaction.
   603  func TestIssueExportTx(t *testing.T) {
   604  	require := require.New(t)
   605  
   606  	env := setup(t, &envConfig{fork: durango})
   607  	defer env.vm.ctx.Lock.Unlock()
   608  
   609  	genesisTx := getCreateTxFromGenesisTest(t, env.genesisBytes, "AVAX")
   610  
   611  	var (
   612  		avaxID     = genesisTx.ID()
   613  		key        = keys[0]
   614  		kc         = secp256k1fx.NewKeychain(key)
   615  		to         = key.PublicKey().Address()
   616  		changeAddr = to
   617  	)
   618  
   619  	tx, err := env.txBuilder.ExportTx(
   620  		constants.PlatformChainID,
   621  		to, // to
   622  		avaxID,
   623  		startBalance-env.vm.TxFee,
   624  		kc,
   625  		changeAddr,
   626  	)
   627  	require.NoError(err)
   628  
   629  	peerSharedMemory := env.sharedMemory.NewSharedMemory(constants.PlatformChainID)
   630  	utxoBytes, _, _, err := peerSharedMemory.Indexed(
   631  		env.vm.ctx.ChainID,
   632  		[][]byte{
   633  			key.PublicKey().Address().Bytes(),
   634  		},
   635  		nil,
   636  		nil,
   637  		math.MaxInt32,
   638  	)
   639  	require.NoError(err)
   640  	require.Empty(utxoBytes)
   641  
   642  	env.vm.ctx.Lock.Unlock()
   643  
   644  	issueAndAccept(require, env.vm, env.issuer, tx)
   645  
   646  	env.vm.ctx.Lock.Lock()
   647  
   648  	utxoBytes, _, _, err = peerSharedMemory.Indexed(
   649  		env.vm.ctx.ChainID,
   650  		[][]byte{
   651  			key.PublicKey().Address().Bytes(),
   652  		},
   653  		nil,
   654  		nil,
   655  		math.MaxInt32,
   656  	)
   657  	require.NoError(err)
   658  	require.Len(utxoBytes, 1)
   659  }
   660  
   661  func TestClearForceAcceptedExportTx(t *testing.T) {
   662  	require := require.New(t)
   663  
   664  	env := setup(t, &envConfig{
   665  		fork: latest,
   666  	})
   667  	defer env.vm.ctx.Lock.Unlock()
   668  
   669  	genesisTx := getCreateTxFromGenesisTest(t, env.genesisBytes, "AVAX")
   670  
   671  	var (
   672  		avaxID     = genesisTx.ID()
   673  		assetID    = avax.Asset{ID: avaxID}
   674  		key        = keys[0]
   675  		kc         = secp256k1fx.NewKeychain(key)
   676  		to         = key.PublicKey().Address()
   677  		changeAddr = to
   678  	)
   679  
   680  	tx, err := env.txBuilder.ExportTx(
   681  		constants.PlatformChainID,
   682  		to, // to
   683  		avaxID,
   684  		startBalance-env.vm.TxFee,
   685  		kc,
   686  		changeAddr,
   687  	)
   688  	require.NoError(err)
   689  
   690  	utxo := avax.UTXOID{
   691  		TxID:        tx.ID(),
   692  		OutputIndex: 0,
   693  	}
   694  	utxoID := utxo.InputID()
   695  
   696  	peerSharedMemory := env.sharedMemory.NewSharedMemory(constants.PlatformChainID)
   697  	require.NoError(peerSharedMemory.Apply(map[ids.ID]*atomic.Requests{
   698  		env.vm.ctx.ChainID: {
   699  			RemoveRequests: [][]byte{utxoID[:]},
   700  		},
   701  	}))
   702  
   703  	_, err = peerSharedMemory.Get(env.vm.ctx.ChainID, [][]byte{utxoID[:]})
   704  	require.ErrorIs(err, database.ErrNotFound)
   705  
   706  	env.vm.ctx.Lock.Unlock()
   707  
   708  	issueAndAccept(require, env.vm, env.issuer, tx)
   709  
   710  	env.vm.ctx.Lock.Lock()
   711  
   712  	_, err = peerSharedMemory.Get(env.vm.ctx.ChainID, [][]byte{utxoID[:]})
   713  	require.ErrorIs(err, database.ErrNotFound)
   714  
   715  	assertIndexedTX(t, env.vm.db, 0, key.PublicKey().Address(), assetID.AssetID(), tx.ID())
   716  	assertLatestIdx(t, env.vm.db, key.PublicKey().Address(), assetID.AssetID(), 1)
   717  }