github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/evm_test.go (about)

     1  package evm_test
     2  
     3  import (
     4  	"encoding/binary"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"math"
     8  	"math/big"
     9  	"testing"
    10  
    11  	"github.com/onflow/cadence/runtime/common"
    12  
    13  	"github.com/onflow/cadence/encoding/ccf"
    14  	gethTypes "github.com/onflow/go-ethereum/core/types"
    15  	"github.com/onflow/go-ethereum/rlp"
    16  	"github.com/stretchr/testify/assert"
    17  
    18  	"github.com/onflow/cadence"
    19  	"github.com/onflow/cadence/encoding/json"
    20  	"github.com/stretchr/testify/require"
    21  
    22  	"github.com/onflow/flow-go/engine/execution/testutil"
    23  	"github.com/onflow/flow-go/fvm"
    24  	"github.com/onflow/flow-go/fvm/crypto"
    25  	envMock "github.com/onflow/flow-go/fvm/environment/mock"
    26  	"github.com/onflow/flow-go/fvm/evm"
    27  	"github.com/onflow/flow-go/fvm/evm/stdlib"
    28  	"github.com/onflow/flow-go/fvm/evm/testutils"
    29  	. "github.com/onflow/flow-go/fvm/evm/testutils"
    30  	"github.com/onflow/flow-go/fvm/evm/types"
    31  	"github.com/onflow/flow-go/fvm/storage/snapshot"
    32  	"github.com/onflow/flow-go/fvm/systemcontracts"
    33  	"github.com/onflow/flow-go/model/flow"
    34  	"github.com/onflow/flow-go/utils/unittest"
    35  )
    36  
    37  func TestEVMRun(t *testing.T) {
    38  	t.Parallel()
    39  
    40  	chain := flow.Emulator.Chain()
    41  	t.Run("testing EVM.run (happy case)", func(t *testing.T) {
    42  
    43  		t.Parallel()
    44  		RunWithNewEnvironment(t,
    45  			chain, func(
    46  				ctx fvm.Context,
    47  				vm fvm.VM,
    48  				snapshot snapshot.SnapshotTree,
    49  				testContract *TestContract,
    50  				testAccount *EOATestAccount,
    51  			) {
    52  				sc := systemcontracts.SystemContractsForChain(chain.ChainID())
    53  				code := []byte(fmt.Sprintf(
    54  					`
    55  					import EVM from %s
    56  
    57  					transaction(tx: [UInt8], coinbaseBytes: [UInt8; 20]){
    58  						prepare(account: &Account) {
    59  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
    60  							let res = EVM.run(tx: tx, coinbase: coinbase)
    61  
    62  							assert(res.status == EVM.Status.successful, message: "unexpected status")
    63  							assert(res.errorCode == 0, message: "unexpected error code")
    64  							assert(res.deployedContract == nil, message: "unexpected deployed contract")
    65  						}
    66  					}
    67  					`,
    68  					sc.EVMContract.Address.HexWithPrefix(),
    69  				))
    70  
    71  				num := int64(12)
    72  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
    73  					testContract.DeployedAt.ToCommon(),
    74  					testContract.MakeCallData(t, "store", big.NewInt(num)),
    75  					big.NewInt(0),
    76  					uint64(100_000),
    77  					big.NewInt(0),
    78  				)
    79  
    80  				innerTx := cadence.NewArray(
    81  					ConvertToCadence(innerTxBytes),
    82  				).WithType(stdlib.EVMTransactionBytesCadenceType)
    83  
    84  				coinbase := cadence.NewArray(
    85  					ConvertToCadence(testAccount.Address().Bytes()),
    86  				).WithType(stdlib.EVMAddressBytesCadenceType)
    87  
    88  				tx := fvm.Transaction(
    89  					flow.NewTransactionBody().
    90  						SetScript(code).
    91  						AddAuthorizer(sc.FlowServiceAccount.Address).
    92  						AddArgument(json.MustEncode(innerTx)).
    93  						AddArgument(json.MustEncode(coinbase)),
    94  					0)
    95  
    96  				state, output, err := vm.Run(
    97  					ctx,
    98  					tx,
    99  					snapshot)
   100  				require.NoError(t, err)
   101  				require.NoError(t, output.Err)
   102  				require.NotEmpty(t, state.WriteSet)
   103  
   104  				// assert event fiedls are correct
   105  				require.Len(t, output.Events, 2)
   106  
   107  				blockEvent := output.Events[1]
   108  
   109  				assert.Equal(
   110  					t,
   111  					common.NewAddressLocation(
   112  						nil,
   113  						common.Address(sc.EVMContract.Address),
   114  						string(types.EventTypeBlockExecuted),
   115  					).ID(),
   116  					string(blockEvent.Type),
   117  				)
   118  
   119  				ev, err := ccf.Decode(nil, blockEvent.Payload)
   120  				require.NoError(t, err)
   121  				cadenceEvent, ok := ev.(cadence.Event)
   122  				require.True(t, ok)
   123  
   124  				blockEventPayload, err := types.DecodeBlockEventPayload(cadenceEvent)
   125  				require.NoError(t, err)
   126  				require.NotEmpty(t, blockEventPayload.Hash)
   127  
   128  				txEvent := output.Events[0]
   129  
   130  				assert.Equal(
   131  					t,
   132  					common.NewAddressLocation(
   133  						nil,
   134  						common.Address(sc.EVMContract.Address),
   135  						string(types.EventTypeTransactionExecuted),
   136  					).ID(),
   137  					string(txEvent.Type),
   138  				)
   139  
   140  				ev, err = ccf.Decode(nil, txEvent.Payload)
   141  				require.NoError(t, err)
   142  				cadenceEvent, ok = ev.(cadence.Event)
   143  				require.True(t, ok)
   144  
   145  				txEventPayload, err := types.DecodeTransactionEventPayload(cadenceEvent)
   146  				require.NoError(t, err)
   147  				require.NotEmpty(t, txEventPayload.Hash)
   148  				require.Equal(t, hex.EncodeToString(innerTxBytes), txEventPayload.Payload)
   149  				require.Equal(t, uint16(types.ErrCodeNoError), txEventPayload.ErrorCode)
   150  				require.Equal(t, uint16(0), txEventPayload.Index)
   151  				require.Equal(t, blockEventPayload.Hash, txEventPayload.BlockHash)
   152  				require.Equal(t, blockEventPayload.Height, txEventPayload.BlockHeight)
   153  				require.Equal(t, blockEventPayload.TotalGasUsed, txEventPayload.GasConsumed)
   154  				require.Empty(t, txEventPayload.ContractAddress)
   155  
   156  				// append the state
   157  				snapshot = snapshot.Append(state)
   158  
   159  				// query the value
   160  				code = []byte(fmt.Sprintf(
   161  					`
   162  					import EVM from %s
   163  					access(all)
   164  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): EVM.Result {
   165  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   166  						let res = EVM.run(tx: tx, coinbase: coinbase)
   167  
   168  						assert(res.status == EVM.Status.successful, message: "unexpected status")
   169  						assert(res.errorCode == 0, message: "unexpected error code")
   170  						
   171  						return res
   172  					}
   173  					`,
   174  					sc.EVMContract.Address.HexWithPrefix(),
   175  				))
   176  
   177  				innerTxBytes = testAccount.PrepareSignAndEncodeTx(t,
   178  					testContract.DeployedAt.ToCommon(),
   179  					testContract.MakeCallData(t, "retrieve"),
   180  					big.NewInt(0),
   181  					uint64(100_000),
   182  					big.NewInt(0),
   183  				)
   184  
   185  				innerTx = cadence.NewArray(
   186  					ConvertToCadence(innerTxBytes),
   187  				).WithType(stdlib.EVMTransactionBytesCadenceType)
   188  
   189  				script := fvm.Script(code).WithArguments(
   190  					json.MustEncode(innerTx),
   191  					json.MustEncode(coinbase),
   192  				)
   193  
   194  				_, output, err = vm.Run(
   195  					ctx,
   196  					script,
   197  					snapshot)
   198  				require.NoError(t, err)
   199  				require.NoError(t, output.Err)
   200  
   201  				res, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
   202  				require.NoError(t, err)
   203  				require.Equal(t, types.StatusSuccessful, res.Status)
   204  				require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
   205  				require.Nil(t, res.DeployedContractAddress)
   206  				require.Equal(t, num, new(big.Int).SetBytes(res.ReturnedValue).Int64())
   207  			})
   208  	})
   209  
   210  	t.Run("testing EVM.run (failed)", func(t *testing.T) {
   211  		t.Parallel()
   212  		RunWithNewEnvironment(t,
   213  			chain, func(
   214  				ctx fvm.Context,
   215  				vm fvm.VM,
   216  				snapshot snapshot.SnapshotTree,
   217  				testContract *TestContract,
   218  				testAccount *EOATestAccount,
   219  			) {
   220  				sc := systemcontracts.SystemContractsForChain(chain.ChainID())
   221  				code := []byte(fmt.Sprintf(
   222  					`
   223  					import EVM from %s
   224  
   225  					transaction(tx: [UInt8], coinbaseBytes: [UInt8; 20]){
   226  						prepare(account: &Account) {
   227  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   228  							let res = EVM.run(tx: tx, coinbase: coinbase)
   229  
   230  							assert(res.status == EVM.Status.failed, message: "unexpected status")
   231  							// ExecutionErrCodeExecutionReverted
   232  							assert(res.errorCode == %d, message: "unexpected error code")
   233  						}
   234  					}
   235  					`,
   236  					sc.EVMContract.Address.HexWithPrefix(),
   237  					types.ExecutionErrCodeExecutionReverted,
   238  				))
   239  
   240  				num := int64(12)
   241  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
   242  					testContract.DeployedAt.ToCommon(),
   243  					testContract.MakeCallData(t, "storeButRevert", big.NewInt(num)),
   244  					big.NewInt(0),
   245  					uint64(100_000),
   246  					big.NewInt(0),
   247  				)
   248  
   249  				innerTx := cadence.NewArray(
   250  					ConvertToCadence(innerTxBytes),
   251  				).WithType(stdlib.EVMTransactionBytesCadenceType)
   252  
   253  				coinbase := cadence.NewArray(
   254  					ConvertToCadence(testAccount.Address().Bytes()),
   255  				).WithType(stdlib.EVMAddressBytesCadenceType)
   256  
   257  				tx := fvm.Transaction(
   258  					flow.NewTransactionBody().
   259  						SetScript(code).
   260  						AddAuthorizer(sc.FlowServiceAccount.Address).
   261  						AddArgument(json.MustEncode(innerTx)).
   262  						AddArgument(json.MustEncode(coinbase)),
   263  					0)
   264  
   265  				state, output, err := vm.Run(
   266  					ctx,
   267  					tx,
   268  					snapshot)
   269  				require.NoError(t, err)
   270  				require.NoError(t, output.Err)
   271  				require.NotEmpty(t, state.WriteSet)
   272  
   273  				snapshot = snapshot.Append(state)
   274  
   275  				// query the value
   276  				code = []byte(fmt.Sprintf(
   277  					`
   278  					import EVM from %s
   279  					access(all)
   280  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): EVM.Result {
   281  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   282  						return EVM.run(tx: tx, coinbase: coinbase)
   283  					}
   284  				`,
   285  					sc.EVMContract.Address.HexWithPrefix(),
   286  				))
   287  
   288  				innerTxBytes = testAccount.PrepareSignAndEncodeTx(t,
   289  					testContract.DeployedAt.ToCommon(),
   290  					testContract.MakeCallData(t, "retrieve"),
   291  					big.NewInt(0),
   292  					uint64(100_000),
   293  					big.NewInt(0),
   294  				)
   295  
   296  				innerTx = cadence.NewArray(
   297  					ConvertToCadence(innerTxBytes),
   298  				).WithType(stdlib.EVMTransactionBytesCadenceType)
   299  
   300  				script := fvm.Script(code).WithArguments(
   301  					json.MustEncode(innerTx),
   302  					json.MustEncode(coinbase),
   303  				)
   304  
   305  				_, output, err = vm.Run(
   306  					ctx,
   307  					script,
   308  					snapshot)
   309  				require.NoError(t, err)
   310  				require.NoError(t, output.Err)
   311  
   312  				res, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
   313  				require.NoError(t, err)
   314  				require.Equal(t, types.StatusSuccessful, res.Status)
   315  				require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
   316  				require.Equal(t, int64(0), new(big.Int).SetBytes(res.ReturnedValue).Int64())
   317  			})
   318  	})
   319  
   320  	t.Run("testing EVM.run (with event emitted)", func(t *testing.T) {
   321  		t.Parallel()
   322  		RunWithNewEnvironment(t,
   323  			chain, func(
   324  				ctx fvm.Context,
   325  				vm fvm.VM,
   326  				snapshot snapshot.SnapshotTree,
   327  				testContract *TestContract,
   328  				testAccount *EOATestAccount,
   329  			) {
   330  				sc := systemcontracts.SystemContractsForChain(chain.ChainID())
   331  				code := []byte(fmt.Sprintf(
   332  					`
   333  					import EVM from %s
   334  
   335  					transaction(tx: [UInt8], coinbaseBytes: [UInt8; 20]){
   336  						prepare(account: &Account) {
   337  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   338  							let res = EVM.run(tx: tx, coinbase: coinbase)
   339  
   340  							assert(res.status == EVM.Status.successful, message: "unexpected status")
   341  							assert(res.errorCode == 0, message: "unexpected error code")
   342  						}
   343  					}
   344  					`,
   345  					sc.EVMContract.Address.HexWithPrefix(),
   346  				))
   347  
   348  				num := int64(12)
   349  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
   350  					testContract.DeployedAt.ToCommon(),
   351  					testContract.MakeCallData(t, "storeWithLog", big.NewInt(num)),
   352  					big.NewInt(0),
   353  					uint64(100_000),
   354  					big.NewInt(0),
   355  				)
   356  
   357  				innerTx := cadence.NewArray(
   358  					ConvertToCadence(innerTxBytes),
   359  				).WithType(stdlib.EVMTransactionBytesCadenceType)
   360  
   361  				coinbase := cadence.NewArray(
   362  					ConvertToCadence(testAccount.Address().Bytes()),
   363  				).WithType(stdlib.EVMAddressBytesCadenceType)
   364  
   365  				tx := fvm.Transaction(
   366  					flow.NewTransactionBody().
   367  						SetScript(code).
   368  						AddAuthorizer(sc.FlowServiceAccount.Address).
   369  						AddArgument(json.MustEncode(innerTx)).
   370  						AddArgument(json.MustEncode(coinbase)),
   371  					0)
   372  
   373  				state, output, err := vm.Run(
   374  					ctx,
   375  					tx,
   376  					snapshot)
   377  				require.NoError(t, err)
   378  				require.NoError(t, output.Err)
   379  				require.NotEmpty(t, state.WriteSet)
   380  
   381  				txEvent := output.Events[0]
   382  				ev, err := ccf.Decode(nil, txEvent.Payload)
   383  				require.NoError(t, err)
   384  				cadenceEvent, ok := ev.(cadence.Event)
   385  				require.True(t, ok)
   386  
   387  				event, err := types.DecodeTransactionEventPayload(cadenceEvent)
   388  				require.NoError(t, err)
   389  				require.NotEmpty(t, event.Hash)
   390  
   391  				encodedLogs, err := hex.DecodeString(event.Logs)
   392  				require.NoError(t, err)
   393  
   394  				var logs []*gethTypes.Log
   395  				err = rlp.DecodeBytes(encodedLogs, &logs)
   396  				require.NoError(t, err)
   397  				require.Len(t, logs, 1)
   398  				log := logs[0]
   399  				last := log.Topics[len(log.Topics)-1] // last topic is the value set in the store method
   400  				assert.Equal(t, num, last.Big().Int64())
   401  			})
   402  	})
   403  }
   404  
   405  func TestEVMBatchRun(t *testing.T) {
   406  	chain := flow.Emulator.Chain()
   407  
   408  	// run a batch of valid transactions which update a value on the contract
   409  	// after the batch is run check that the value updated on the contract matches
   410  	// the last transaction update in the batch.
   411  	t.Run("Batch run multiple valid transactions", func(t *testing.T) {
   412  		t.Parallel()
   413  		RunWithNewEnvironment(t,
   414  			chain, func(
   415  				ctx fvm.Context,
   416  				vm fvm.VM,
   417  				snapshot snapshot.SnapshotTree,
   418  				testContract *TestContract,
   419  				testAccount *EOATestAccount,
   420  			) {
   421  				sc := systemcontracts.SystemContractsForChain(chain.ChainID())
   422  				batchRunCode := []byte(fmt.Sprintf(
   423  					`
   424  					import EVM from %s
   425  
   426  					transaction(txs: [[UInt8]], coinbaseBytes: [UInt8; 20]) {
   427  						prepare(account: &Account) {
   428  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   429  							let batchResults = EVM.batchRun(txs: txs, coinbase: coinbase)
   430  							
   431  							assert(batchResults.length == txs.length, message: "invalid result length")
   432  							for res in batchResults {
   433  								assert(res.status == EVM.Status.successful, message: "unexpected status")
   434  								assert(res.errorCode == 0, message: "unexpected error code")
   435  							}
   436  						}
   437  					}
   438  					`,
   439  					sc.EVMContract.Address.HexWithPrefix(),
   440  				))
   441  
   442  				batchCount := 5
   443  				var storedValues []int64
   444  				txBytes := make([]cadence.Value, batchCount)
   445  				for i := 0; i < batchCount; i++ {
   446  					num := int64(i)
   447  					storedValues = append(storedValues, num)
   448  					// prepare batch of transaction payloads
   449  					tx := testAccount.PrepareSignAndEncodeTx(t,
   450  						testContract.DeployedAt.ToCommon(),
   451  						testContract.MakeCallData(t, "storeWithLog", big.NewInt(num)),
   452  						big.NewInt(0),
   453  						uint64(100_000),
   454  						big.NewInt(0),
   455  					)
   456  
   457  					// build txs argument
   458  					txBytes[i] = cadence.NewArray(
   459  						ConvertToCadence(tx),
   460  					).WithType(stdlib.EVMTransactionBytesCadenceType)
   461  				}
   462  
   463  				coinbase := cadence.NewArray(
   464  					ConvertToCadence(testAccount.Address().Bytes()),
   465  				).WithType(stdlib.EVMAddressBytesCadenceType)
   466  
   467  				txs := cadence.NewArray(txBytes).
   468  					WithType(cadence.NewVariableSizedArrayType(
   469  						stdlib.EVMTransactionBytesCadenceType,
   470  					))
   471  
   472  				tx := fvm.Transaction(
   473  					flow.NewTransactionBody().
   474  						SetScript(batchRunCode).
   475  						AddAuthorizer(sc.FlowServiceAccount.Address).
   476  						AddArgument(json.MustEncode(txs)).
   477  						AddArgument(json.MustEncode(coinbase)),
   478  					0)
   479  
   480  				state, output, err := vm.Run(ctx, tx, snapshot)
   481  				require.NoError(t, err)
   482  				require.NoError(t, output.Err)
   483  				require.NotEmpty(t, state.WriteSet)
   484  
   485  				require.Len(t, output.Events, batchCount+1) // +1 block executed
   486  				for i, event := range output.Events {
   487  					if i == batchCount { // last one is block executed
   488  						continue
   489  					}
   490  
   491  					ev, err := ccf.Decode(nil, event.Payload)
   492  					require.NoError(t, err)
   493  					cadenceEvent, ok := ev.(cadence.Event)
   494  					require.True(t, ok)
   495  
   496  					event, err := types.DecodeTransactionEventPayload(cadenceEvent)
   497  					require.NoError(t, err)
   498  
   499  					encodedLogs, err := hex.DecodeString(event.Logs)
   500  					require.NoError(t, err)
   501  
   502  					var logs []*gethTypes.Log
   503  					err = rlp.DecodeBytes(encodedLogs, &logs)
   504  					require.NoError(t, err)
   505  
   506  					require.Len(t, logs, 1)
   507  
   508  					log := logs[0]
   509  					last := log.Topics[len(log.Topics)-1] // last topic is the value set in the store method
   510  					assert.Equal(t, storedValues[i], last.Big().Int64())
   511  				}
   512  
   513  				// append the state
   514  				snapshot = snapshot.Append(state)
   515  
   516  				// retrieve the values
   517  				retrieveCode := []byte(fmt.Sprintf(
   518  					`
   519  						import EVM from %s
   520  						access(all)
   521  						fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): EVM.Result {
   522  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   523  							return EVM.run(tx: tx, coinbase: coinbase)
   524  						}
   525  					`,
   526  					sc.EVMContract.Address.HexWithPrefix(),
   527  				))
   528  
   529  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
   530  					testContract.DeployedAt.ToCommon(),
   531  					testContract.MakeCallData(t, "retrieve"),
   532  					big.NewInt(0),
   533  					uint64(100_000),
   534  					big.NewInt(0),
   535  				)
   536  
   537  				innerTx := cadence.NewArray(
   538  					ConvertToCadence(innerTxBytes),
   539  				).WithType(stdlib.EVMTransactionBytesCadenceType)
   540  
   541  				script := fvm.Script(retrieveCode).WithArguments(
   542  					json.MustEncode(innerTx),
   543  					json.MustEncode(coinbase),
   544  				)
   545  
   546  				_, output, err = vm.Run(
   547  					ctx,
   548  					script,
   549  					snapshot)
   550  				require.NoError(t, err)
   551  				require.NoError(t, output.Err)
   552  
   553  				// make sure the retrieved value is the same as the last value
   554  				// that was stored by transaction batch
   555  				res, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
   556  				require.NoError(t, err)
   557  				require.Equal(t, types.StatusSuccessful, res.Status)
   558  				require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
   559  				require.Equal(t, storedValues[len(storedValues)-1], new(big.Int).SetBytes(res.ReturnedValue).Int64())
   560  			})
   561  	})
   562  
   563  	// run batch with one invalid transaction that has an invalid nonce
   564  	// this should produce invalid result on that specific transaction
   565  	// but other transaction should successfuly update the value on the contract
   566  	t.Run("Batch run with one invalid transaction", func(t *testing.T) {
   567  		t.Parallel()
   568  		RunWithNewEnvironment(t,
   569  			chain, func(
   570  				ctx fvm.Context,
   571  				vm fvm.VM,
   572  				snapshot snapshot.SnapshotTree,
   573  				testContract *TestContract,
   574  				testAccount *EOATestAccount,
   575  			) {
   576  				// we make transaction at specific index invalid to fail
   577  				const failedTxIndex = 3
   578  				sc := systemcontracts.SystemContractsForChain(chain.ChainID())
   579  				batchRunCode := []byte(fmt.Sprintf(
   580  					`
   581  					import EVM from %s
   582  
   583  					transaction(txs: [[UInt8]], coinbaseBytes: [UInt8; 20]) {
   584  						prepare(account: &Account) {
   585  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   586  							let batchResults = EVM.batchRun(txs: txs, coinbase: coinbase)
   587  							
   588  							assert(batchResults.length == txs.length, message: "invalid result length")
   589  							for i, res in batchResults {
   590  								if i != %d {
   591  									assert(res.status == EVM.Status.successful, message: "unexpected status")
   592  									assert(res.errorCode == 0, message: "unexpected error code")
   593  								} else {
   594  									assert(res.status == EVM.Status.invalid, message: "unexpected status")
   595  									assert(res.errorCode == 201, message: "unexpected error code")
   596  								}
   597  							}
   598  						}
   599  					}
   600  					`,
   601  					sc.EVMContract.Address.HexWithPrefix(),
   602  					failedTxIndex,
   603  				))
   604  
   605  				batchCount := 5
   606  				var num int64
   607  				txBytes := make([]cadence.Value, batchCount)
   608  				for i := 0; i < batchCount; i++ {
   609  					num = int64(i)
   610  
   611  					if i == failedTxIndex {
   612  						// make one transaction in the batch have an invalid nonce
   613  						testAccount.SetNonce(testAccount.Nonce() - 1)
   614  					}
   615  					// prepare batch of transaction payloads
   616  					tx := testAccount.PrepareSignAndEncodeTx(t,
   617  						testContract.DeployedAt.ToCommon(),
   618  						testContract.MakeCallData(t, "store", big.NewInt(num)),
   619  						big.NewInt(0),
   620  						uint64(100_000),
   621  						big.NewInt(0),
   622  					)
   623  
   624  					// build txs argument
   625  					txBytes[i] = cadence.NewArray(
   626  						ConvertToCadence(tx),
   627  					).WithType(stdlib.EVMTransactionBytesCadenceType)
   628  				}
   629  
   630  				coinbase := cadence.NewArray(
   631  					ConvertToCadence(testAccount.Address().Bytes()),
   632  				).WithType(stdlib.EVMAddressBytesCadenceType)
   633  
   634  				txs := cadence.NewArray(txBytes).
   635  					WithType(cadence.NewVariableSizedArrayType(
   636  						stdlib.EVMTransactionBytesCadenceType,
   637  					))
   638  
   639  				tx := fvm.Transaction(
   640  					flow.NewTransactionBody().
   641  						SetScript(batchRunCode).
   642  						AddAuthorizer(sc.FlowServiceAccount.Address).
   643  						AddArgument(json.MustEncode(txs)).
   644  						AddArgument(json.MustEncode(coinbase)),
   645  					0)
   646  
   647  				state, output, err := vm.Run(ctx, tx, snapshot)
   648  				require.NoError(t, err)
   649  				require.NoError(t, output.Err)
   650  				require.NotEmpty(t, state.WriteSet)
   651  
   652  				// append the state
   653  				snapshot = snapshot.Append(state)
   654  
   655  				// retrieve the values
   656  				retrieveCode := []byte(fmt.Sprintf(
   657  					`
   658  						import EVM from %s
   659  						access(all)
   660  						fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): EVM.Result {
   661  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   662  							return EVM.run(tx: tx, coinbase: coinbase)
   663  						}
   664  					`,
   665  					sc.EVMContract.Address.HexWithPrefix(),
   666  				))
   667  
   668  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
   669  					testContract.DeployedAt.ToCommon(),
   670  					testContract.MakeCallData(t, "retrieve"),
   671  					big.NewInt(0),
   672  					uint64(100_000),
   673  					big.NewInt(0),
   674  				)
   675  
   676  				innerTx := cadence.NewArray(
   677  					ConvertToCadence(innerTxBytes),
   678  				).WithType(stdlib.EVMTransactionBytesCadenceType)
   679  
   680  				script := fvm.Script(retrieveCode).WithArguments(
   681  					json.MustEncode(innerTx),
   682  					json.MustEncode(coinbase),
   683  				)
   684  
   685  				_, output, err = vm.Run(
   686  					ctx,
   687  					script,
   688  					snapshot)
   689  				require.NoError(t, err)
   690  				require.NoError(t, output.Err)
   691  
   692  				// make sure the retrieved value is the same as the last value
   693  				// that was stored by transaction batch
   694  				res, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
   695  				require.NoError(t, err)
   696  				require.Equal(t, types.StatusSuccessful, res.Status)
   697  				require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
   698  				require.Equal(t, num, new(big.Int).SetBytes(res.ReturnedValue).Int64())
   699  			})
   700  	})
   701  
   702  	// fail every other transaction with gas set too low for execution to succeed
   703  	// but high enough to pass intristic gas check, then check the updated values on the
   704  	// contract to match the last successful transaction execution
   705  	t.Run("Batch run with with failed transactions", func(t *testing.T) {
   706  		t.Parallel()
   707  		RunWithNewEnvironment(t,
   708  			chain, func(
   709  				ctx fvm.Context,
   710  				vm fvm.VM,
   711  				snapshot snapshot.SnapshotTree,
   712  				testContract *TestContract,
   713  				testAccount *EOATestAccount,
   714  			) {
   715  				sc := systemcontracts.SystemContractsForChain(chain.ChainID())
   716  				batchRunCode := []byte(fmt.Sprintf(
   717  					`
   718  					import EVM from %s
   719  
   720  					transaction(txs: [[UInt8]], coinbaseBytes: [UInt8; 20]) {
   721  						execute {
   722  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   723  							let batchResults = EVM.batchRun(txs: txs, coinbase: coinbase)
   724  
   725  							log("results")
   726  							log(batchResults)
   727  							assert(batchResults.length == txs.length, message: "invalid result length")
   728  
   729  							for i, res in batchResults {
   730  								if i %% 2 != 0 {
   731  									assert(res.status == EVM.Status.successful, message: "unexpected success status")
   732  									assert(res.errorCode == 0, message: "unexpected error code")
   733  								} else {
   734  									assert(res.status == EVM.Status.failed, message: "unexpected failed status")
   735  									assert(res.errorCode == 301, message: "unexpected error code")
   736  								}
   737  							}
   738  						}
   739  					}
   740  					`,
   741  					sc.EVMContract.Address.HexWithPrefix(),
   742  				))
   743  
   744  				batchCount := 6
   745  				var num int64
   746  				txBytes := make([]cadence.Value, batchCount)
   747  				for i := 0; i < batchCount; i++ {
   748  					gas := uint64(100_000)
   749  					if i%2 == 0 {
   750  						// fail with too low gas limit
   751  						gas = 22_000
   752  					} else {
   753  						// update number with only valid transactions
   754  						num = int64(i)
   755  					}
   756  
   757  					// prepare batch of transaction payloads
   758  					tx := testAccount.PrepareSignAndEncodeTx(t,
   759  						testContract.DeployedAt.ToCommon(),
   760  						testContract.MakeCallData(t, "store", big.NewInt(num)),
   761  						big.NewInt(0),
   762  						gas,
   763  						big.NewInt(0),
   764  					)
   765  
   766  					// build txs argument
   767  					txBytes[i] = cadence.NewArray(
   768  						ConvertToCadence(tx),
   769  					).WithType(stdlib.EVMTransactionBytesCadenceType)
   770  				}
   771  
   772  				coinbase := cadence.NewArray(
   773  					ConvertToCadence(testAccount.Address().Bytes()),
   774  				).WithType(stdlib.EVMAddressBytesCadenceType)
   775  
   776  				txs := cadence.NewArray(txBytes).
   777  					WithType(cadence.NewVariableSizedArrayType(
   778  						stdlib.EVMTransactionBytesCadenceType,
   779  					))
   780  
   781  				tx := fvm.Transaction(
   782  					flow.NewTransactionBody().
   783  						SetScript(batchRunCode).
   784  						AddArgument(json.MustEncode(txs)).
   785  						AddArgument(json.MustEncode(coinbase)),
   786  					0)
   787  
   788  				state, output, err := vm.Run(ctx, tx, snapshot)
   789  
   790  				require.NoError(t, err)
   791  				require.NoError(t, output.Err)
   792  				//require.NotEmpty(t, state.WriteSet)
   793  
   794  				// append the state
   795  				snapshot = snapshot.Append(state)
   796  
   797  				// retrieve the values
   798  				retrieveCode := []byte(fmt.Sprintf(
   799  					`
   800  						import EVM from %s
   801  						access(all)
   802  						fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): EVM.Result {
   803  							let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   804  							return EVM.run(tx: tx, coinbase: coinbase)
   805  						}
   806  					`,
   807  					sc.EVMContract.Address.HexWithPrefix(),
   808  				))
   809  
   810  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
   811  					testContract.DeployedAt.ToCommon(),
   812  					testContract.MakeCallData(t, "retrieve"),
   813  					big.NewInt(0),
   814  					uint64(100_000),
   815  					big.NewInt(0),
   816  				)
   817  
   818  				innerTx := cadence.NewArray(
   819  					ConvertToCadence(innerTxBytes),
   820  				).WithType(stdlib.EVMTransactionBytesCadenceType)
   821  
   822  				script := fvm.Script(retrieveCode).WithArguments(
   823  					json.MustEncode(innerTx),
   824  					json.MustEncode(coinbase),
   825  				)
   826  
   827  				_, output, err = vm.Run(
   828  					ctx,
   829  					script,
   830  					snapshot)
   831  				require.NoError(t, err)
   832  				require.NoError(t, output.Err)
   833  
   834  				// make sure the retrieved value is the same as the last value
   835  				// that was stored by transaction batch
   836  				res, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
   837  				require.NoError(t, err)
   838  				require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
   839  				require.Equal(t, types.StatusSuccessful, res.Status)
   840  				require.Equal(t, num, new(big.Int).SetBytes(res.ReturnedValue).Int64())
   841  			})
   842  	})
   843  }
   844  
   845  func TestEVMBlockData(t *testing.T) {
   846  	t.Parallel()
   847  	chain := flow.Emulator.Chain()
   848  	sc := systemcontracts.SystemContractsForChain(chain.ChainID())
   849  	RunWithNewEnvironment(t,
   850  		chain, func(
   851  			ctx fvm.Context,
   852  			vm fvm.VM,
   853  			snapshot snapshot.SnapshotTree,
   854  			testContract *TestContract,
   855  			testAccount *EOATestAccount,
   856  		) {
   857  
   858  			// query the block timestamp
   859  			code := []byte(fmt.Sprintf(
   860  				`
   861  					import EVM from %s
   862  					access(all)
   863  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): EVM.Result {
   864  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
   865  						return EVM.run(tx: tx, coinbase: coinbase)
   866  					}
   867  				`,
   868  				sc.EVMContract.Address.HexWithPrefix(),
   869  			))
   870  
   871  			innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
   872  				testContract.DeployedAt.ToCommon(),
   873  				testContract.MakeCallData(t, "blockTime"),
   874  				big.NewInt(0),
   875  				uint64(100_000),
   876  				big.NewInt(0),
   877  			)
   878  
   879  			coinbase := cadence.NewArray(
   880  				ConvertToCadence(testAccount.Address().Bytes()),
   881  			).WithType(stdlib.EVMAddressBytesCadenceType)
   882  
   883  			innerTx := cadence.NewArray(
   884  				ConvertToCadence(innerTxBytes),
   885  			).WithType(stdlib.EVMTransactionBytesCadenceType)
   886  
   887  			script := fvm.Script(code).WithArguments(
   888  				json.MustEncode(innerTx),
   889  				json.MustEncode(coinbase),
   890  			)
   891  
   892  			_, output, err := vm.Run(
   893  				ctx,
   894  				script,
   895  				snapshot)
   896  			require.NoError(t, err)
   897  			require.NoError(t, output.Err)
   898  
   899  			res, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
   900  			require.NoError(t, err)
   901  			require.Equal(t, types.StatusSuccessful, res.Status)
   902  			require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
   903  			require.Equal(t, ctx.BlockHeader.Timestamp.Unix(), new(big.Int).SetBytes(res.ReturnedValue).Int64())
   904  
   905  		})
   906  }
   907  
   908  func TestEVMAddressDeposit(t *testing.T) {
   909  
   910  	t.Parallel()
   911  	chain := flow.Emulator.Chain()
   912  	sc := systemcontracts.SystemContractsForChain(chain.ChainID())
   913  	RunWithNewEnvironment(t,
   914  		chain, func(
   915  			ctx fvm.Context,
   916  			vm fvm.VM,
   917  			snapshot snapshot.SnapshotTree,
   918  			testContract *TestContract,
   919  			testAccount *EOATestAccount,
   920  		) {
   921  
   922  			code := []byte(fmt.Sprintf(
   923  				`
   924  				import EVM from %s
   925  				import FlowToken from %s
   926  
   927  				transaction(addr: [UInt8; 20]) {
   928  					prepare(account: auth(BorrowValue) &Account) {
   929  						let admin = account.storage
   930  							.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
   931  
   932  						let minter <- admin.createNewMinter(allowedAmount: 1.0)
   933  						let vault <- minter.mintTokens(amount: 1.0)
   934  						destroy minter
   935  
   936  						let address = EVM.EVMAddress(bytes: addr)
   937  						address.deposit(from: <-vault)
   938  					}
   939  				}
   940  			`,
   941  				sc.EVMContract.Address.HexWithPrefix(),
   942  				sc.FlowToken.Address.HexWithPrefix(),
   943  			))
   944  
   945  			addr := RandomAddress(t)
   946  
   947  			tx := fvm.Transaction(
   948  				flow.NewTransactionBody().
   949  					SetScript(code).
   950  					AddAuthorizer(sc.FlowServiceAccount.Address).
   951  					AddArgument(json.MustEncode(cadence.NewArray(
   952  						ConvertToCadence(addr.Bytes()),
   953  					).WithType(stdlib.EVMAddressBytesCadenceType))),
   954  				0)
   955  
   956  			execSnap, output, err := vm.Run(
   957  				ctx,
   958  				tx,
   959  				snapshot)
   960  			require.NoError(t, err)
   961  			require.NoError(t, output.Err)
   962  
   963  			snapshot = snapshot.Append(execSnap)
   964  
   965  			expectedBalance := types.OneFlowBalance
   966  			bal := getEVMAccountBalance(t, ctx, vm, snapshot, addr)
   967  			require.Equal(t, expectedBalance, bal)
   968  		})
   969  }
   970  
   971  func TestCOAAddressDeposit(t *testing.T) {
   972  	t.Parallel()
   973  
   974  	chain := flow.Emulator.Chain()
   975  	sc := systemcontracts.SystemContractsForChain(chain.ChainID())
   976  	RunWithNewEnvironment(t,
   977  		chain, func(
   978  			ctx fvm.Context,
   979  			vm fvm.VM,
   980  			snapshot snapshot.SnapshotTree,
   981  			testContract *TestContract,
   982  			testAccount *EOATestAccount,
   983  		) {
   984  			code := []byte(fmt.Sprintf(
   985  				`
   986  				import EVM from %s
   987  				import FlowToken from %s
   988  
   989  				access(all)
   990  				fun main() {
   991  					let admin = getAuthAccount<auth(BorrowValue) &Account>(%s)
   992  						.storage.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
   993  					let minter <- admin.createNewMinter(allowedAmount: 1.23)
   994  					let vault <- minter.mintTokens(amount: 1.23)
   995  					destroy minter
   996  
   997  					let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount()
   998  					cadenceOwnedAccount.deposit(from: <-vault)
   999  					destroy cadenceOwnedAccount
  1000  				}
  1001                  `,
  1002  				sc.EVMContract.Address.HexWithPrefix(),
  1003  				sc.FlowToken.Address.HexWithPrefix(),
  1004  				sc.FlowServiceAccount.Address.HexWithPrefix(),
  1005  			))
  1006  
  1007  			script := fvm.Script(code)
  1008  
  1009  			_, output, err := vm.Run(
  1010  				ctx,
  1011  				script,
  1012  				snapshot)
  1013  			require.NoError(t, err)
  1014  			require.NoError(t, output.Err)
  1015  
  1016  		})
  1017  }
  1018  
  1019  func TestCadenceOwnedAccountFunctionalities(t *testing.T) {
  1020  	t.Parallel()
  1021  	chain := flow.Emulator.Chain()
  1022  	sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1023  
  1024  	t.Run("test coa setup", func(t *testing.T) {
  1025  		t.Parallel()
  1026  
  1027  		RunWithNewEnvironment(t,
  1028  			chain, func(
  1029  				ctx fvm.Context,
  1030  				vm fvm.VM,
  1031  				snapshot snapshot.SnapshotTree,
  1032  				testContract *TestContract,
  1033  				testAccount *EOATestAccount,
  1034  			) {
  1035  				// create a flow account
  1036  				flowAccount, _, snapshot := createAndFundFlowAccount(
  1037  					t,
  1038  					ctx,
  1039  					vm,
  1040  					snapshot,
  1041  				)
  1042  
  1043  				var coaAddress types.Address
  1044  
  1045  				initNonce := uint64(1)
  1046  				// 10 Flow in UFix64
  1047  				initBalanceInUFix64 := uint64(1_000_000_000)
  1048  				initBalance := types.NewBalanceFromUFix64(cadence.UFix64(initBalanceInUFix64))
  1049  
  1050  				coaAddress, snapshot = setupCOA(
  1051  					t,
  1052  					ctx,
  1053  					vm,
  1054  					snapshot,
  1055  					flowAccount,
  1056  					initBalanceInUFix64)
  1057  
  1058  				bal := getEVMAccountBalance(
  1059  					t,
  1060  					ctx,
  1061  					vm,
  1062  					snapshot,
  1063  					coaAddress)
  1064  				require.Equal(t, initBalance, bal)
  1065  
  1066  				nonce := getEVMAccountNonce(
  1067  					t,
  1068  					ctx,
  1069  					vm,
  1070  					snapshot,
  1071  					coaAddress)
  1072  				require.Equal(t, initNonce, nonce)
  1073  			})
  1074  	})
  1075  
  1076  	t.Run("test coa withdraw", func(t *testing.T) {
  1077  		t.Parallel()
  1078  
  1079  		RunWithNewEnvironment(t,
  1080  			chain, func(
  1081  				ctx fvm.Context,
  1082  				vm fvm.VM,
  1083  				snapshot snapshot.SnapshotTree,
  1084  				testContract *TestContract,
  1085  				testAccount *EOATestAccount,
  1086  			) {
  1087  				code := []byte(fmt.Sprintf(
  1088  					`
  1089  				import EVM from %s
  1090  				import FlowToken from %s
  1091  
  1092  				access(all)
  1093  				fun main(): UFix64 {
  1094  					let admin = getAuthAccount<auth(BorrowValue) &Account>(%s)
  1095  						.storage.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
  1096  					let minter <- admin.createNewMinter(allowedAmount: 2.34)
  1097  					let vault <- minter.mintTokens(amount: 2.34)
  1098  					destroy minter
  1099  
  1100  					let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount()
  1101  					cadenceOwnedAccount.deposit(from: <-vault)
  1102  
  1103  					let bal = EVM.Balance(attoflow: 0)
  1104  					bal.setFLOW(flow: 1.23)
  1105  					let vault2 <- cadenceOwnedAccount.withdraw(balance: bal)
  1106  					let balance = vault2.balance
  1107  					destroy cadenceOwnedAccount
  1108  					destroy vault2
  1109  
  1110  					return balance
  1111  				}
  1112  				`,
  1113  					sc.EVMContract.Address.HexWithPrefix(),
  1114  					sc.FlowToken.Address.HexWithPrefix(),
  1115  					sc.FlowServiceAccount.Address.HexWithPrefix(),
  1116  				))
  1117  
  1118  				script := fvm.Script(code)
  1119  
  1120  				_, output, err := vm.Run(
  1121  					ctx,
  1122  					script,
  1123  					snapshot)
  1124  				require.NoError(t, err)
  1125  				require.NoError(t, output.Err)
  1126  			})
  1127  	})
  1128  
  1129  	t.Run("test coa transfer", func(t *testing.T) {
  1130  		t.Parallel()
  1131  
  1132  		RunWithNewEnvironment(t,
  1133  			chain, func(
  1134  				ctx fvm.Context,
  1135  				vm fvm.VM,
  1136  				snapshot snapshot.SnapshotTree,
  1137  				testContract *TestContract,
  1138  				testAccount *EOATestAccount,
  1139  			) {
  1140  				code := []byte(fmt.Sprintf(
  1141  					`
  1142  				import EVM from %s
  1143  				import FlowToken from %s
  1144  
  1145  				access(all)
  1146  				fun main(address: [UInt8; 20]): UFix64 {
  1147  					let admin = getAuthAccount<auth(BorrowValue) &Account>(%s)
  1148  						.storage.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
  1149  
  1150  					let minter <- admin.createNewMinter(allowedAmount: 2.34)
  1151  					let vault <- minter.mintTokens(amount: 2.34)
  1152  					destroy minter
  1153  
  1154  					let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount()
  1155  					cadenceOwnedAccount.deposit(from: <-vault)
  1156  
  1157  					let bal = EVM.Balance(attoflow: 0)
  1158  					bal.setFLOW(flow: 1.23)
  1159  
  1160  					let recipientEVMAddress = EVM.EVMAddress(bytes: address)
  1161  
  1162  					let res = cadenceOwnedAccount.call(
  1163  						to: recipientEVMAddress,
  1164  						data: [],
  1165  						gasLimit: 100_000,
  1166  						value: bal,
  1167  					)
  1168  
  1169  					assert(res.status == EVM.Status.successful, message: "transfer call was not successful")
  1170  
  1171  					destroy cadenceOwnedAccount
  1172  					return recipientEVMAddress.balance().inFLOW()
  1173  				}
  1174  				`,
  1175  					sc.EVMContract.Address.HexWithPrefix(),
  1176  					sc.FlowToken.Address.HexWithPrefix(),
  1177  					sc.FlowServiceAccount.Address.HexWithPrefix(),
  1178  				))
  1179  
  1180  				addr := cadence.NewArray(
  1181  					ConvertToCadence(testutils.RandomAddress(t).Bytes()),
  1182  				).WithType(stdlib.EVMAddressBytesCadenceType)
  1183  
  1184  				script := fvm.Script(code).WithArguments(
  1185  					json.MustEncode(addr),
  1186  				)
  1187  
  1188  				_, output, err := vm.Run(
  1189  					ctx,
  1190  					script,
  1191  					snapshot)
  1192  				require.NoError(t, err)
  1193  				require.NoError(t, output.Err)
  1194  
  1195  				require.Equal(t, uint64(123000000), uint64(output.Value.(cadence.UFix64)))
  1196  			})
  1197  	})
  1198  
  1199  	t.Run("test coa deposit and withdraw in a single transaction", func(t *testing.T) {
  1200  		RunWithNewEnvironment(t,
  1201  			chain, func(
  1202  				ctx fvm.Context,
  1203  				vm fvm.VM,
  1204  				snapshot snapshot.SnapshotTree,
  1205  				testContract *TestContract,
  1206  				testAccount *EOATestAccount,
  1207  			) {
  1208  				code := []byte(fmt.Sprintf(
  1209  					`
  1210  				import EVM from %s
  1211  				import FlowToken from %s
  1212  
  1213  				access(all)
  1214  				fun main(): UFix64 {
  1215  					let admin = getAuthAccount<auth(Storage) &Account>(%s)
  1216  						.storage.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
  1217  
  1218  					let minter <- admin.createNewMinter(allowedAmount: 2.34)
  1219  					let vault <- minter.mintTokens(amount: 2.34)
  1220  					destroy minter
  1221  
  1222  					let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount()
  1223  					cadenceOwnedAccount.deposit(from: <-vault)
  1224  
  1225  					let bal = EVM.Balance(attoflow: 0)
  1226  					bal.setFLOW(flow: 1.23)
  1227  					let vault2 <- cadenceOwnedAccount.withdraw(balance: bal)
  1228  					let balance = vault2.balance
  1229  					destroy cadenceOwnedAccount
  1230  					destroy vault2
  1231  
  1232  					return balance
  1233  				}
  1234  				`,
  1235  					sc.EVMContract.Address.HexWithPrefix(),
  1236  					sc.FlowToken.Address.HexWithPrefix(),
  1237  					sc.FlowServiceAccount.Address.HexWithPrefix(),
  1238  				))
  1239  
  1240  				script := fvm.Script(code)
  1241  
  1242  				_, output, err := vm.Run(
  1243  					ctx,
  1244  					script,
  1245  					snapshot)
  1246  				require.NoError(t, err)
  1247  				require.NoError(t, output.Err)
  1248  			})
  1249  	})
  1250  
  1251  	t.Run("test coa deploy", func(t *testing.T) {
  1252  		RunWithNewEnvironment(t,
  1253  			chain, func(
  1254  				ctx fvm.Context,
  1255  				vm fvm.VM,
  1256  				snapshot snapshot.SnapshotTree,
  1257  				testContract *TestContract,
  1258  				testAccount *EOATestAccount,
  1259  			) {
  1260  				code := []byte(fmt.Sprintf(
  1261  					`
  1262  					import EVM from %s
  1263  					import FlowToken from %s
  1264  	
  1265  					access(all)
  1266  					fun main(code: [UInt8]): EVM.Result {
  1267  						let admin = getAuthAccount<auth(Storage) &Account>(%s)
  1268  							.storage.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
  1269  						let minter <- admin.createNewMinter(allowedAmount: 2.34)
  1270  						let vault <- minter.mintTokens(amount: 2.34)
  1271  						destroy minter
  1272  	
  1273  						let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount()
  1274  						cadenceOwnedAccount.deposit(from: <-vault)
  1275  	
  1276  						let res = cadenceOwnedAccount.deploy(
  1277  							code: code,
  1278  							gasLimit: 1000000,
  1279  							value: EVM.Balance(attoflow: 1230000000000000000)
  1280  						)
  1281  						destroy cadenceOwnedAccount
  1282  						return res
  1283  					}
  1284  					`,
  1285  					sc.EVMContract.Address.HexWithPrefix(),
  1286  					sc.FlowToken.Address.HexWithPrefix(),
  1287  					sc.FlowServiceAccount.Address.HexWithPrefix(),
  1288  				))
  1289  
  1290  				script := fvm.Script(code).
  1291  					WithArguments(json.MustEncode(
  1292  						cadence.NewArray(
  1293  							ConvertToCadence(testContract.ByteCode),
  1294  						).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type)),
  1295  					))
  1296  
  1297  				_, output, err := vm.Run(
  1298  					ctx,
  1299  					script,
  1300  					snapshot)
  1301  				require.NoError(t, err)
  1302  				require.NoError(t, output.Err)
  1303  
  1304  				res, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
  1305  				require.NoError(t, err)
  1306  				require.Equal(t, types.StatusSuccessful, res.Status)
  1307  				require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
  1308  				require.NotNil(t, res.DeployedContractAddress)
  1309  				// we strip away first few bytes because they contain deploy code
  1310  				require.Equal(t, testContract.ByteCode[17:], []byte(res.ReturnedValue))
  1311  			})
  1312  	})
  1313  }
  1314  
  1315  func TestDryRun(t *testing.T) {
  1316  	t.Parallel()
  1317  	chain := flow.Emulator.Chain()
  1318  	sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1319  	evmAddress := sc.EVMContract.Address.HexWithPrefix()
  1320  
  1321  	dryRunTx := func(
  1322  		t *testing.T,
  1323  		tx *gethTypes.Transaction,
  1324  		ctx fvm.Context,
  1325  		vm fvm.VM,
  1326  		snapshot snapshot.SnapshotTree,
  1327  		testContract *TestContract,
  1328  	) *types.ResultSummary {
  1329  		code := []byte(fmt.Sprintf(`
  1330  			import EVM from %s
  1331  
  1332  			access(all)
  1333  			fun main(tx: [UInt8]): EVM.Result {
  1334  				return EVM.dryRun(
  1335  					tx: tx, 
  1336  					from: EVM.EVMAddress(bytes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
  1337  				)
  1338  			}`,
  1339  			evmAddress,
  1340  		))
  1341  
  1342  		innerTxBytes, err := tx.MarshalBinary()
  1343  		require.NoError(t, err)
  1344  
  1345  		script := fvm.Script(code).WithArguments(
  1346  			json.MustEncode(
  1347  				cadence.NewArray(
  1348  					ConvertToCadence(innerTxBytes),
  1349  				).WithType(stdlib.EVMTransactionBytesCadenceType),
  1350  			),
  1351  		)
  1352  		_, output, err := vm.Run(
  1353  			ctx,
  1354  			script,
  1355  			snapshot)
  1356  		require.NoError(t, err)
  1357  		require.NoError(t, output.Err)
  1358  
  1359  		result, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
  1360  		require.NoError(t, err)
  1361  		return result
  1362  	}
  1363  
  1364  	// this test checks that gas limit is correctly used and gas usage correctly reported
  1365  	t.Run("test dry run storing a value with different gas limits", func(t *testing.T) {
  1366  		RunWithNewEnvironment(t,
  1367  			chain, func(
  1368  				ctx fvm.Context,
  1369  				vm fvm.VM,
  1370  				snapshot snapshot.SnapshotTree,
  1371  				testContract *TestContract,
  1372  				testAccount *EOATestAccount,
  1373  			) {
  1374  				data := testContract.MakeCallData(t, "store", big.NewInt(1337))
  1375  
  1376  				limit := uint64(math.MaxUint64 - 1)
  1377  				tx := gethTypes.NewTransaction(
  1378  					0,
  1379  					testContract.DeployedAt.ToCommon(),
  1380  					big.NewInt(0),
  1381  					limit,
  1382  					big.NewInt(0),
  1383  					data,
  1384  				)
  1385  				result := dryRunTx(t, tx, ctx, vm, snapshot, testContract)
  1386  				require.Equal(t, types.ErrCodeNoError, result.ErrorCode)
  1387  				require.Equal(t, types.StatusSuccessful, result.Status)
  1388  				require.Greater(t, result.GasConsumed, uint64(0))
  1389  				require.Less(t, result.GasConsumed, limit)
  1390  
  1391  				// gas limit too low, but still bigger than intrinsic gas value
  1392  				limit = uint64(21216)
  1393  				tx = gethTypes.NewTransaction(
  1394  					0,
  1395  					testContract.DeployedAt.ToCommon(),
  1396  					big.NewInt(0),
  1397  					limit,
  1398  					big.NewInt(0),
  1399  					data,
  1400  				)
  1401  				result = dryRunTx(t, tx, ctx, vm, snapshot, testContract)
  1402  				require.Equal(t, types.ExecutionErrCodeOutOfGas, result.ErrorCode)
  1403  				require.Equal(t, types.StatusFailed, result.Status)
  1404  				require.Equal(t, result.GasConsumed, limit) // burn it all!!!
  1405  			})
  1406  	})
  1407  
  1408  	// this test makes sure the dry-run that updates the value on the contract
  1409  	// doesn't persist the change, and after when the value is read it isn't updated.
  1410  	t.Run("test dry run for any side-effects", func(t *testing.T) {
  1411  		RunWithNewEnvironment(t,
  1412  			chain, func(
  1413  				ctx fvm.Context,
  1414  				vm fvm.VM,
  1415  				snapshot snapshot.SnapshotTree,
  1416  				testContract *TestContract,
  1417  				testAccount *EOATestAccount,
  1418  			) {
  1419  				updatedValue := int64(1337)
  1420  				data := testContract.MakeCallData(t, "store", big.NewInt(updatedValue))
  1421  				tx := gethTypes.NewTransaction(
  1422  					0,
  1423  					testContract.DeployedAt.ToCommon(),
  1424  					big.NewInt(0),
  1425  					uint64(1000000),
  1426  					big.NewInt(0),
  1427  					data,
  1428  				)
  1429  
  1430  				result := dryRunTx(t, tx, ctx, vm, snapshot, testContract)
  1431  				require.Equal(t, types.ErrCodeNoError, result.ErrorCode)
  1432  				require.Equal(t, types.StatusSuccessful, result.Status)
  1433  				require.Greater(t, result.GasConsumed, uint64(0))
  1434  
  1435  				// query the value make sure it's not updated
  1436  				code := []byte(fmt.Sprintf(
  1437  					`
  1438  					import EVM from %s
  1439  					access(all)
  1440  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): EVM.Result {
  1441  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
  1442  						return EVM.run(tx: tx, coinbase: coinbase)
  1443  					}
  1444  					`,
  1445  					evmAddress,
  1446  				))
  1447  
  1448  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
  1449  					testContract.DeployedAt.ToCommon(),
  1450  					testContract.MakeCallData(t, "retrieve"),
  1451  					big.NewInt(0),
  1452  					uint64(100_000),
  1453  					big.NewInt(0),
  1454  				)
  1455  
  1456  				innerTx := cadence.NewArray(
  1457  					ConvertToCadence(innerTxBytes),
  1458  				).WithType(stdlib.EVMTransactionBytesCadenceType)
  1459  
  1460  				coinbase := cadence.NewArray(
  1461  					ConvertToCadence(testAccount.Address().Bytes()),
  1462  				).WithType(stdlib.EVMAddressBytesCadenceType)
  1463  
  1464  				script := fvm.Script(code).WithArguments(
  1465  					json.MustEncode(innerTx),
  1466  					json.MustEncode(coinbase),
  1467  				)
  1468  
  1469  				_, output, err := vm.Run(
  1470  					ctx,
  1471  					script,
  1472  					snapshot)
  1473  				require.NoError(t, err)
  1474  				require.NoError(t, output.Err)
  1475  
  1476  				res, err := stdlib.ResultSummaryFromEVMResultValue(output.Value)
  1477  				require.NoError(t, err)
  1478  				require.Equal(t, types.StatusSuccessful, res.Status)
  1479  				require.Equal(t, types.ErrCodeNoError, res.ErrorCode)
  1480  				// make sure the value we used in the dry-run is not the same as the value stored in contract
  1481  				require.NotEqual(t, updatedValue, new(big.Int).SetBytes(res.ReturnedValue).Int64())
  1482  			})
  1483  	})
  1484  
  1485  	t.Run("test dry run contract deployment", func(t *testing.T) {
  1486  		RunWithNewEnvironment(t,
  1487  			chain, func(
  1488  				ctx fvm.Context,
  1489  				vm fvm.VM,
  1490  				snapshot snapshot.SnapshotTree,
  1491  				testContract *TestContract,
  1492  				testAccount *EOATestAccount,
  1493  			) {
  1494  				tx := gethTypes.NewContractCreation(
  1495  					0,
  1496  					big.NewInt(0),
  1497  					uint64(1000000),
  1498  					big.NewInt(0),
  1499  					testContract.ByteCode,
  1500  				)
  1501  
  1502  				result := dryRunTx(t, tx, ctx, vm, snapshot, testContract)
  1503  				require.Equal(t, types.ErrCodeNoError, result.ErrorCode)
  1504  				require.Equal(t, types.StatusSuccessful, result.Status)
  1505  				require.Greater(t, result.GasConsumed, uint64(0))
  1506  				require.NotNil(t, result.ReturnedValue)
  1507  				require.NotNil(t, result.DeployedContractAddress)
  1508  				require.NotEmpty(t, result.DeployedContractAddress.String())
  1509  			})
  1510  	})
  1511  
  1512  	t.Run("test dry run validation error", func(t *testing.T) {
  1513  		RunWithNewEnvironment(t,
  1514  			chain, func(
  1515  				ctx fvm.Context,
  1516  				vm fvm.VM,
  1517  				snapshot snapshot.SnapshotTree,
  1518  				testContract *TestContract,
  1519  				testAccount *EOATestAccount,
  1520  			) {
  1521  				tx := gethTypes.NewContractCreation(
  1522  					0,
  1523  					big.NewInt(100), // more than available
  1524  					uint64(1000000),
  1525  					big.NewInt(0),
  1526  					nil,
  1527  				)
  1528  
  1529  				result := dryRunTx(t, tx, ctx, vm, snapshot, testContract)
  1530  				assert.Equal(t, types.ValidationErrCodeInsufficientFunds, result.ErrorCode)
  1531  				assert.Equal(t, types.StatusInvalid, result.Status)
  1532  				assert.Equal(t, types.InvalidTransactionGasCost, int(result.GasConsumed))
  1533  			})
  1534  	})
  1535  }
  1536  
  1537  func TestCadenceArch(t *testing.T) {
  1538  	t.Parallel()
  1539  
  1540  	t.Run("testing calling Cadence arch - flow block height (happy case)", func(t *testing.T) {
  1541  		chain := flow.Emulator.Chain()
  1542  		sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1543  		RunWithNewEnvironment(t,
  1544  			chain, func(
  1545  				ctx fvm.Context,
  1546  				vm fvm.VM,
  1547  				snapshot snapshot.SnapshotTree,
  1548  				testContract *TestContract,
  1549  				testAccount *EOATestAccount,
  1550  			) {
  1551  				code := []byte(fmt.Sprintf(
  1552  					`
  1553  					import EVM from %s
  1554  
  1555  					access(all)
  1556  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]) {
  1557  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
  1558  						let res = EVM.run(tx: tx, coinbase: coinbase)
  1559  						assert(res.status == EVM.Status.successful, message: "test failed: ".concat(res.errorCode.toString()))
  1560  					}
  1561                      `,
  1562  					sc.EVMContract.Address.HexWithPrefix(),
  1563  				))
  1564  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
  1565  					testContract.DeployedAt.ToCommon(),
  1566  					testContract.MakeCallData(t, "verifyArchCallToFlowBlockHeight", ctx.BlockHeader.Height),
  1567  					big.NewInt(0),
  1568  					uint64(10_000_000),
  1569  					big.NewInt(0),
  1570  				)
  1571  				script := fvm.Script(code).WithArguments(
  1572  					json.MustEncode(
  1573  						cadence.NewArray(
  1574  							ConvertToCadence(innerTxBytes),
  1575  						).WithType(stdlib.EVMTransactionBytesCadenceType),
  1576  					),
  1577  					json.MustEncode(
  1578  						cadence.NewArray(
  1579  							ConvertToCadence(testAccount.Address().Bytes()),
  1580  						).WithType(stdlib.EVMAddressBytesCadenceType),
  1581  					),
  1582  				)
  1583  				_, output, err := vm.Run(
  1584  					ctx,
  1585  					script,
  1586  					snapshot)
  1587  				require.NoError(t, err)
  1588  				require.NoError(t, output.Err)
  1589  			})
  1590  	})
  1591  
  1592  	t.Run("testing calling Cadence arch - revertible random", func(t *testing.T) {
  1593  		chain := flow.Emulator.Chain()
  1594  		sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1595  		RunWithNewEnvironment(t,
  1596  			chain, func(
  1597  				ctx fvm.Context,
  1598  				vm fvm.VM,
  1599  				snapshot snapshot.SnapshotTree,
  1600  				testContract *TestContract,
  1601  				testAccount *EOATestAccount,
  1602  			) {
  1603  				code := []byte(fmt.Sprintf(
  1604  					`
  1605  					import EVM from %s
  1606  
  1607  					access(all)
  1608  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): [UInt8] {
  1609  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
  1610  						let res = EVM.run(tx: tx, coinbase: coinbase)
  1611  						assert(res.status == EVM.Status.successful, message: "test failed: ".concat(res.errorCode.toString()))
  1612  						return res.data
  1613  					}
  1614                      `,
  1615  					sc.EVMContract.Address.HexWithPrefix(),
  1616  				))
  1617  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
  1618  					testContract.DeployedAt.ToCommon(),
  1619  					testContract.MakeCallData(t, "verifyArchCallToRevertibleRandom"),
  1620  					big.NewInt(0),
  1621  					uint64(10_000_000),
  1622  					big.NewInt(0),
  1623  				)
  1624  				script := fvm.Script(code).WithArguments(
  1625  					json.MustEncode(
  1626  						cadence.NewArray(
  1627  							ConvertToCadence(innerTxBytes),
  1628  						).WithType(stdlib.EVMTransactionBytesCadenceType),
  1629  					),
  1630  					json.MustEncode(
  1631  						cadence.NewArray(
  1632  							ConvertToCadence(testAccount.Address().Bytes()),
  1633  						).WithType(stdlib.EVMAddressBytesCadenceType),
  1634  					),
  1635  				)
  1636  				_, output, err := vm.Run(
  1637  					ctx,
  1638  					script,
  1639  					snapshot)
  1640  				require.NoError(t, err)
  1641  				require.NoError(t, output.Err)
  1642  
  1643  				res := make([]byte, 8)
  1644  				vals := output.Value.(cadence.Array).Values
  1645  				vals = vals[len(vals)-8:] // only last 8 bytes is the value
  1646  				for i := range res {
  1647  					res[i] = byte(vals[i].(cadence.UInt8))
  1648  				}
  1649  
  1650  				actualRand := binary.BigEndian.Uint64(res)
  1651  				// because PRG uses script ID and random source we can not predict the random
  1652  				// we can set the random source but since script ID is generated by hashing
  1653  				// script and args, and since arg is a signed transaction which always changes
  1654  				// we can't fix the value
  1655  				require.Greater(t, actualRand, uint64(0))
  1656  			})
  1657  	})
  1658  
  1659  	t.Run("testing calling Cadence arch - random source (happy case)", func(t *testing.T) {
  1660  		chain := flow.Emulator.Chain()
  1661  		sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1662  		RunWithNewEnvironment(t,
  1663  			chain, func(
  1664  				ctx fvm.Context,
  1665  				vm fvm.VM,
  1666  				snapshot snapshot.SnapshotTree,
  1667  				testContract *TestContract,
  1668  				testAccount *EOATestAccount,
  1669  			) {
  1670  				entropy := []byte{13, 37}
  1671  				source := []byte{91, 161, 206, 171, 100, 17, 141, 44} // coresponding out to the above entropy
  1672  
  1673  				// we must record a new heartbeat with a fixed block, we manually execute a transaction to do so,
  1674  				// since doing this automatically would require a block computer and whole execution setup
  1675  				height := uint64(1)
  1676  				block1 := unittest.BlockFixture()
  1677  				block1.Header.Height = height
  1678  				ctx.BlockHeader = block1.Header
  1679  				ctx.EntropyProvider = testutil.EntropyProviderFixture(entropy) // fix the entropy
  1680  
  1681  				txBody := flow.NewTransactionBody().
  1682  					SetScript([]byte(fmt.Sprintf(`
  1683  						import RandomBeaconHistory from %s
  1684  
  1685  						transaction {
  1686  							prepare(serviceAccount: auth(Capabilities, Storage) &Account) {
  1687  								let randomBeaconHistoryHeartbeat = serviceAccount.storage.borrow<&RandomBeaconHistory.Heartbeat>(
  1688  									from: RandomBeaconHistory.HeartbeatStoragePath)
  1689  										?? panic("Couldn't borrow RandomBeaconHistory.Heartbeat Resource")
  1690  								randomBeaconHistoryHeartbeat.heartbeat(randomSourceHistory: randomSourceHistory())
  1691  							}
  1692  						}`, sc.RandomBeaconHistory.Address.HexWithPrefix())),
  1693  					).
  1694  					AddAuthorizer(sc.FlowServiceAccount.Address)
  1695  
  1696  				s, out, err := vm.Run(ctx, fvm.Transaction(txBody, 0), snapshot)
  1697  				require.NoError(t, err)
  1698  				require.NoError(t, out.Err)
  1699  
  1700  				snapshot = snapshot.Append(s)
  1701  
  1702  				code := []byte(fmt.Sprintf(
  1703  					`
  1704  					import EVM from %s
  1705  
  1706  					access(all)
  1707  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]): [UInt8] {
  1708  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
  1709  						let res = EVM.run(tx: tx, coinbase: coinbase)
  1710  						assert(res.status == EVM.Status.successful, message: "evm tx wrong status")
  1711  						return res.data
  1712  					}
  1713                      `,
  1714  					sc.EVMContract.Address.HexWithPrefix(),
  1715  				))
  1716  
  1717  				// we fake progressing to new block height since random beacon does the check the
  1718  				// current height (2) is bigger than the height requested (1)
  1719  				block1.Header.Height = 2
  1720  				ctx.BlockHeader = block1.Header
  1721  
  1722  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
  1723  					testContract.DeployedAt.ToCommon(),
  1724  					testContract.MakeCallData(t, "verifyArchCallToRandomSource", height),
  1725  					big.NewInt(0),
  1726  					uint64(10_000_000),
  1727  					big.NewInt(0),
  1728  				)
  1729  				script := fvm.Script(code).WithArguments(
  1730  					json.MustEncode(
  1731  						cadence.NewArray(
  1732  							ConvertToCadence(innerTxBytes),
  1733  						).WithType(stdlib.EVMTransactionBytesCadenceType),
  1734  					),
  1735  					json.MustEncode(
  1736  						cadence.NewArray(
  1737  							ConvertToCadence(testAccount.Address().Bytes()),
  1738  						).WithType(stdlib.EVMAddressBytesCadenceType),
  1739  					),
  1740  				)
  1741  				_, output, err := vm.Run(
  1742  					ctx,
  1743  					script,
  1744  					snapshot)
  1745  				require.NoError(t, err)
  1746  				require.NoError(t, output.Err)
  1747  
  1748  				res := make([]byte, 8)
  1749  				vals := output.Value.(cadence.Array).Values
  1750  				vals = vals[len(vals)-8:] // only last 8 bytes is the value
  1751  				for i := range res {
  1752  					res[i] = byte(vals[i].(cadence.UInt8))
  1753  				}
  1754  				require.Equal(t, source, res)
  1755  			})
  1756  	})
  1757  
  1758  	t.Run("testing calling Cadence arch - random source (failed due to incorrect height)", func(t *testing.T) {
  1759  		chain := flow.Emulator.Chain()
  1760  		sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1761  		RunWithNewEnvironment(t,
  1762  			chain, func(
  1763  				ctx fvm.Context,
  1764  				vm fvm.VM,
  1765  				snapshot snapshot.SnapshotTree,
  1766  				testContract *TestContract,
  1767  				testAccount *EOATestAccount,
  1768  			) {
  1769  				// we must record a new heartbeat with a fixed block, we manually execute a transaction to do so,
  1770  				// since doing this automatically would require a block computer and whole execution setup
  1771  				height := uint64(1)
  1772  				block1 := unittest.BlockFixture()
  1773  				block1.Header.Height = height
  1774  				ctx.BlockHeader = block1.Header
  1775  
  1776  				txBody := flow.NewTransactionBody().
  1777  					SetScript([]byte(fmt.Sprintf(`
  1778  						import RandomBeaconHistory from %s
  1779  
  1780  						transaction {
  1781  							prepare(serviceAccount: auth(Capabilities, Storage) &Account) {
  1782  								let randomBeaconHistoryHeartbeat = serviceAccount.storage.borrow<&RandomBeaconHistory.Heartbeat>(
  1783  									from: RandomBeaconHistory.HeartbeatStoragePath)
  1784  										?? panic("Couldn't borrow RandomBeaconHistory.Heartbeat Resource")
  1785  								randomBeaconHistoryHeartbeat.heartbeat(randomSourceHistory: randomSourceHistory())
  1786  							}
  1787  						}`, sc.RandomBeaconHistory.Address.HexWithPrefix())),
  1788  					).
  1789  					AddAuthorizer(sc.FlowServiceAccount.Address)
  1790  
  1791  				s, out, err := vm.Run(ctx, fvm.Transaction(txBody, 0), snapshot)
  1792  				require.NoError(t, err)
  1793  				require.NoError(t, out.Err)
  1794  
  1795  				snapshot = snapshot.Append(s)
  1796  
  1797  				height = 1337 // invalid
  1798  				// we make sure the transaction fails, due to requested height being invalid
  1799  				code := []byte(fmt.Sprintf(
  1800  					`
  1801  					import EVM from %s
  1802  
  1803  					access(all)
  1804  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]) {
  1805  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
  1806  						let res = EVM.run(tx: tx, coinbase: coinbase)
  1807  					}
  1808                      `,
  1809  					sc.EVMContract.Address.HexWithPrefix(),
  1810  				))
  1811  
  1812  				// we fake progressing to new block height since random beacon does the check the
  1813  				// current height (2) is bigger than the height requested (1)
  1814  				block1.Header.Height = 2
  1815  				ctx.BlockHeader = block1.Header
  1816  
  1817  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
  1818  					testContract.DeployedAt.ToCommon(),
  1819  					testContract.MakeCallData(t, "verifyArchCallToRandomSource", height),
  1820  					big.NewInt(0),
  1821  					uint64(10_000_000),
  1822  					big.NewInt(0),
  1823  				)
  1824  				script := fvm.Script(code).WithArguments(
  1825  					json.MustEncode(
  1826  						cadence.NewArray(
  1827  							ConvertToCadence(innerTxBytes),
  1828  						).WithType(stdlib.EVMTransactionBytesCadenceType),
  1829  					),
  1830  					json.MustEncode(
  1831  						cadence.NewArray(
  1832  							ConvertToCadence(testAccount.Address().Bytes()),
  1833  						).WithType(stdlib.EVMAddressBytesCadenceType),
  1834  					),
  1835  				)
  1836  				_, output, err := vm.Run(
  1837  					ctx,
  1838  					script,
  1839  					snapshot)
  1840  				require.NoError(t, err)
  1841  				// make sure the error is correct
  1842  				require.ErrorContains(t, output.Err, "Source of randomness not yet recorded")
  1843  			})
  1844  	})
  1845  
  1846  	t.Run("testing calling Cadence arch - COA ownership proof (happy case)", func(t *testing.T) {
  1847  		chain := flow.Emulator.Chain()
  1848  		sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1849  		RunWithNewEnvironment(t,
  1850  			chain, func(
  1851  				ctx fvm.Context,
  1852  				vm fvm.VM,
  1853  				snapshot snapshot.SnapshotTree,
  1854  				testContract *TestContract,
  1855  				testAccount *EOATestAccount,
  1856  			) {
  1857  				// create a flow account
  1858  				privateKey, err := testutil.GenerateAccountPrivateKey()
  1859  				require.NoError(t, err)
  1860  
  1861  				snapshot, accounts, err := testutil.CreateAccounts(
  1862  					vm,
  1863  					snapshot,
  1864  					[]flow.AccountPrivateKey{privateKey},
  1865  					chain)
  1866  				require.NoError(t, err)
  1867  				flowAccount := accounts[0]
  1868  
  1869  				// create/store/link coa
  1870  				coaAddress, snapshot := setupCOA(
  1871  					t,
  1872  					ctx,
  1873  					vm,
  1874  					snapshot,
  1875  					flowAccount,
  1876  					0,
  1877  				)
  1878  
  1879  				data := RandomCommonHash(t)
  1880  
  1881  				hasher, err := crypto.NewPrefixedHashing(privateKey.HashAlgo, "FLOW-V0.0-user")
  1882  				require.NoError(t, err)
  1883  
  1884  				sig, err := privateKey.PrivateKey.Sign(data.Bytes(), hasher)
  1885  				require.NoError(t, err)
  1886  
  1887  				proof := types.COAOwnershipProof{
  1888  					KeyIndices:     []uint64{0},
  1889  					Address:        types.FlowAddress(flowAccount),
  1890  					CapabilityPath: "coa",
  1891  					Signatures:     []types.Signature{types.Signature(sig)},
  1892  				}
  1893  
  1894  				encodedProof, err := proof.Encode()
  1895  				require.NoError(t, err)
  1896  
  1897  				// create transaction for proof verification
  1898  				code := []byte(fmt.Sprintf(
  1899  					`
  1900  					import EVM from %s
  1901  
  1902  					access(all)
  1903  					fun main(tx: [UInt8], coinbaseBytes: [UInt8; 20]) {
  1904  						let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
  1905  						let res = EVM.run(tx: tx, coinbase: coinbase)
  1906  						assert(res.status == EVM.Status.successful, message: "test failed: ".concat(res.errorCode.toString()))
  1907  					}
  1908                  	`,
  1909  					sc.EVMContract.Address.HexWithPrefix(),
  1910  				))
  1911  				innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
  1912  					testContract.DeployedAt.ToCommon(),
  1913  					testContract.MakeCallData(t, "verifyArchCallToVerifyCOAOwnershipProof",
  1914  						true,
  1915  						coaAddress.ToCommon(),
  1916  						data,
  1917  						encodedProof),
  1918  					big.NewInt(0),
  1919  					uint64(10_000_000),
  1920  					big.NewInt(0),
  1921  				)
  1922  				verifyScript := fvm.Script(code).WithArguments(
  1923  					json.MustEncode(
  1924  						cadence.NewArray(
  1925  							ConvertToCadence(innerTxBytes),
  1926  						).WithType(
  1927  							stdlib.EVMTransactionBytesCadenceType,
  1928  						)),
  1929  					json.MustEncode(
  1930  						cadence.NewArray(
  1931  							ConvertToCadence(
  1932  								testAccount.Address().Bytes(),
  1933  							),
  1934  						).WithType(
  1935  							stdlib.EVMAddressBytesCadenceType,
  1936  						),
  1937  					),
  1938  				)
  1939  				// run proof transaction
  1940  				_, output, err := vm.Run(
  1941  					ctx,
  1942  					verifyScript,
  1943  					snapshot)
  1944  				require.NoError(t, err)
  1945  				require.NoError(t, output.Err)
  1946  			})
  1947  	})
  1948  }
  1949  
  1950  func createAndFundFlowAccount(
  1951  	t *testing.T,
  1952  	ctx fvm.Context,
  1953  	vm fvm.VM,
  1954  	snapshot snapshot.SnapshotTree,
  1955  ) (flow.Address, flow.AccountPrivateKey, snapshot.SnapshotTree) {
  1956  
  1957  	privateKey, err := testutil.GenerateAccountPrivateKey()
  1958  	require.NoError(t, err)
  1959  
  1960  	snapshot, accounts, err := testutil.CreateAccounts(
  1961  		vm,
  1962  		snapshot,
  1963  		[]flow.AccountPrivateKey{privateKey},
  1964  		ctx.Chain)
  1965  	require.NoError(t, err)
  1966  	flowAccount := accounts[0]
  1967  
  1968  	// fund the account with 100 tokens
  1969  	sc := systemcontracts.SystemContractsForChain(ctx.Chain.ChainID())
  1970  	code := []byte(fmt.Sprintf(
  1971  		`
  1972  		import FlowToken from %s
  1973  		import FungibleToken from %s 
  1974  
  1975  		transaction {
  1976  			prepare(account: auth(BorrowValue) &Account) {
  1977  			let admin = account.storage
  1978  				.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
  1979  
  1980  			let minter <- admin.createNewMinter(allowedAmount: 100.0)
  1981  			let vault <- minter.mintTokens(amount: 100.0)
  1982  
  1983  			let receiverRef = getAccount(%s).capabilities
  1984  				.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
  1985  				?? panic("Could not borrow receiver reference to the recipient's Vault")
  1986  			receiverRef.deposit(from: <-vault)
  1987  
  1988  			destroy minter
  1989  			}
  1990  		}
  1991  		`,
  1992  		sc.FlowToken.Address.HexWithPrefix(),
  1993  		sc.FungibleToken.Address.HexWithPrefix(),
  1994  		flowAccount.HexWithPrefix(),
  1995  	))
  1996  
  1997  	tx := fvm.Transaction(
  1998  		flow.NewTransactionBody().
  1999  			SetScript(code).
  2000  			AddAuthorizer(sc.FlowServiceAccount.Address),
  2001  		0)
  2002  
  2003  	es, output, err := vm.Run(ctx, tx, snapshot)
  2004  	require.NoError(t, err)
  2005  	require.NoError(t, output.Err)
  2006  	snapshot = snapshot.Append(es)
  2007  
  2008  	bal := getFlowAccountBalance(
  2009  		t,
  2010  		ctx,
  2011  		vm,
  2012  		snapshot,
  2013  		flowAccount)
  2014  	// 100 flow in ufix64
  2015  	require.Equal(t, uint64(10_000_000_000), bal)
  2016  
  2017  	return flowAccount, privateKey, snapshot
  2018  }
  2019  
  2020  func setupCOA(
  2021  	t *testing.T,
  2022  	ctx fvm.Context,
  2023  	vm fvm.VM,
  2024  	snap snapshot.SnapshotTree,
  2025  	coaOwner flow.Address,
  2026  	initialFund uint64,
  2027  ) (types.Address, snapshot.SnapshotTree) {
  2028  
  2029  	sc := systemcontracts.SystemContractsForChain(ctx.Chain.ChainID())
  2030  	// create a COA and store it under flow account
  2031  	script := []byte(fmt.Sprintf(
  2032  		`
  2033  	import EVM from %s
  2034  	import FungibleToken from %s
  2035  	import FlowToken from %s
  2036  
  2037  	transaction(amount: UFix64) {
  2038  		prepare(account: auth(Capabilities, Storage) &Account) {
  2039  			let cadenceOwnedAccount1 <- EVM.createCadenceOwnedAccount()
  2040  			
  2041  			let vaultRef = account.storage
  2042                  .borrow<auth(FungibleToken.Withdraw) &FlowToken.Vault>(from: /storage/flowTokenVault)
  2043  				?? panic("Could not borrow reference to the owner's Vault!")
  2044  
  2045  			if amount > 0.0 {
  2046  				let vault <- vaultRef.withdraw(amount: amount) as! @FlowToken.Vault
  2047  				cadenceOwnedAccount1.deposit(from: <-vault)
  2048  			}
  2049  			
  2050  			account.storage.save<@EVM.CadenceOwnedAccount>(
  2051  				<-cadenceOwnedAccount1,
  2052  				to: /storage/coa
  2053  			)
  2054  
  2055  			let cap = account.capabilities.storage
  2056  				.issue<&EVM.CadenceOwnedAccount>(/storage/coa)
  2057  			account.capabilities.publish(cap, at: /public/coa)
  2058  		}
  2059  	}
  2060  	`,
  2061  		sc.EVMContract.Address.HexWithPrefix(),
  2062  		sc.FungibleToken.Address.HexWithPrefix(),
  2063  		sc.FlowToken.Address.HexWithPrefix(),
  2064  	))
  2065  
  2066  	tx := fvm.Transaction(
  2067  		flow.NewTransactionBody().
  2068  			SetScript(script).
  2069  			AddAuthorizer(coaOwner).
  2070  			AddArgument(json.MustEncode(cadence.UFix64(initialFund))),
  2071  		0)
  2072  	es, output, err := vm.Run(ctx, tx, snap)
  2073  	require.NoError(t, err)
  2074  	require.NoError(t, output.Err)
  2075  	snap = snap.Append(es)
  2076  
  2077  	// 3rd event is the cadence owned account created event
  2078  	coaAddress, err := types.COAAddressFromFlowCOACreatedEvent(sc.EVMContract.Address, output.Events[2])
  2079  	require.NoError(t, err)
  2080  
  2081  	return coaAddress, snap
  2082  }
  2083  
  2084  func getFlowAccountBalance(
  2085  	t *testing.T,
  2086  	ctx fvm.Context,
  2087  	vm fvm.VM,
  2088  	snap snapshot.SnapshotTree,
  2089  	address flow.Address,
  2090  ) uint64 {
  2091  	code := []byte(fmt.Sprintf(
  2092  		`
  2093  		access(all) fun main(): UFix64 {
  2094  			return getAccount(%s).balance
  2095  		}
  2096  		`,
  2097  		address.HexWithPrefix(),
  2098  	))
  2099  
  2100  	script := fvm.Script(code)
  2101  	_, output, err := vm.Run(
  2102  		ctx,
  2103  		script,
  2104  		snap)
  2105  	require.NoError(t, err)
  2106  	require.NoError(t, output.Err)
  2107  	val, ok := output.Value.(cadence.UFix64)
  2108  	require.True(t, ok)
  2109  	return uint64(val)
  2110  }
  2111  
  2112  func getEVMAccountBalance(
  2113  	t *testing.T,
  2114  	ctx fvm.Context,
  2115  	vm fvm.VM,
  2116  	snap snapshot.SnapshotTree,
  2117  	address types.Address,
  2118  ) types.Balance {
  2119  	code := []byte(fmt.Sprintf(
  2120  		`
  2121  		import EVM from %s
  2122  		access(all)
  2123  		fun main(addr: [UInt8; 20]): UInt {
  2124  			return EVM.EVMAddress(bytes: addr).balance().inAttoFLOW()
  2125  		}
  2126  		`,
  2127  		systemcontracts.SystemContractsForChain(
  2128  			ctx.Chain.ChainID(),
  2129  		).EVMContract.Address.HexWithPrefix(),
  2130  	))
  2131  
  2132  	script := fvm.Script(code).WithArguments(
  2133  		json.MustEncode(
  2134  			cadence.NewArray(
  2135  				ConvertToCadence(address.Bytes()),
  2136  			).WithType(stdlib.EVMAddressBytesCadenceType),
  2137  		),
  2138  	)
  2139  	_, output, err := vm.Run(
  2140  		ctx,
  2141  		script,
  2142  		snap)
  2143  	require.NoError(t, err)
  2144  	require.NoError(t, output.Err)
  2145  	val, ok := output.Value.(cadence.UInt)
  2146  	require.True(t, ok)
  2147  	return val.Big()
  2148  }
  2149  
  2150  func getEVMAccountNonce(
  2151  	t *testing.T,
  2152  	ctx fvm.Context,
  2153  	vm fvm.VM,
  2154  	snap snapshot.SnapshotTree,
  2155  	address types.Address,
  2156  ) uint64 {
  2157  	code := []byte(fmt.Sprintf(
  2158  		`
  2159  		import EVM from %s
  2160  		access(all)
  2161  		fun main(addr: [UInt8; 20]): UInt64 {
  2162  			return EVM.EVMAddress(bytes: addr).nonce()
  2163  		}
  2164  		`,
  2165  		systemcontracts.SystemContractsForChain(
  2166  			ctx.Chain.ChainID(),
  2167  		).EVMContract.Address.HexWithPrefix(),
  2168  	))
  2169  
  2170  	script := fvm.Script(code).WithArguments(
  2171  		json.MustEncode(
  2172  			cadence.NewArray(
  2173  				ConvertToCadence(address.Bytes()),
  2174  			).WithType(stdlib.EVMAddressBytesCadenceType),
  2175  		),
  2176  	)
  2177  	_, output, err := vm.Run(
  2178  		ctx,
  2179  		script,
  2180  		snap)
  2181  	require.NoError(t, err)
  2182  	require.NoError(t, output.Err)
  2183  	val, ok := output.Value.(cadence.UInt64)
  2184  	require.True(t, ok)
  2185  	return uint64(val)
  2186  }
  2187  
  2188  func RunWithNewEnvironment(
  2189  	t *testing.T,
  2190  	chain flow.Chain,
  2191  	f func(
  2192  		fvm.Context,
  2193  		fvm.VM,
  2194  		snapshot.SnapshotTree,
  2195  		*TestContract,
  2196  		*EOATestAccount,
  2197  	),
  2198  ) {
  2199  	rootAddr, err := evm.StorageAccountAddress(chain.ChainID())
  2200  	require.NoError(t, err)
  2201  
  2202  	RunWithTestBackend(t, func(backend *TestBackend) {
  2203  		RunWithDeployedContract(t, GetStorageTestContract(t), backend, rootAddr, func(testContract *TestContract) {
  2204  			RunWithEOATestAccount(t, backend, rootAddr, func(testAccount *EOATestAccount) {
  2205  
  2206  				blocks := new(envMock.Blocks)
  2207  				block1 := unittest.BlockFixture()
  2208  				blocks.On("ByHeightFrom",
  2209  					block1.Header.Height,
  2210  					block1.Header,
  2211  				).Return(block1.Header, nil)
  2212  
  2213  				opts := []fvm.Option{
  2214  					fvm.WithChain(chain),
  2215  					fvm.WithBlockHeader(block1.Header),
  2216  					fvm.WithAuthorizationChecksEnabled(false),
  2217  					fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
  2218  					fvm.WithEntropyProvider(testutil.EntropyProviderFixture(nil)),
  2219  					fvm.WithRandomSourceHistoryCallAllowed(true),
  2220  					fvm.WithBlocks(blocks),
  2221  					fvm.WithCadenceLogging(true),
  2222  				}
  2223  				ctx := fvm.NewContext(opts...)
  2224  
  2225  				vm := fvm.NewVirtualMachine()
  2226  				snapshotTree := snapshot.NewSnapshotTree(backend)
  2227  
  2228  				baseBootstrapOpts := []fvm.BootstrapProcedureOption{
  2229  					fvm.WithInitialTokenSupply(unittest.GenesisTokenSupply),
  2230  				}
  2231  
  2232  				executionSnapshot, _, err := vm.Run(
  2233  					ctx,
  2234  					fvm.Bootstrap(unittest.ServiceAccountPublicKey, baseBootstrapOpts...),
  2235  					snapshotTree)
  2236  				require.NoError(t, err)
  2237  
  2238  				snapshotTree = snapshotTree.Append(executionSnapshot)
  2239  
  2240  				f(
  2241  					fvm.NewContextFromParent(ctx, fvm.WithEVMEnabled(true)),
  2242  					vm,
  2243  					snapshotTree,
  2244  					testContract,
  2245  					testAccount,
  2246  				)
  2247  			})
  2248  		})
  2249  	})
  2250  }