From 849683aee9ebd3135386e8074b17f0f2f80f3e6e Mon Sep 17 00:00:00 2001 From: ramtinms Date: Wed, 25 Oct 2023 20:21:58 -0700 Subject: [PATCH 1/4] use FVM for integration testing --- fvm/evm/evm_test.go | 145 ++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 74 deletions(-) diff --git a/fvm/evm/evm_test.go b/fvm/evm/evm_test.go index 6962e7360e1..68e7cef31cd 100644 --- a/fvm/evm/evm_test.go +++ b/fvm/evm/evm_test.go @@ -7,16 +7,16 @@ import ( "github.com/onflow/cadence" "github.com/onflow/cadence/encoding/json" - "github.com/onflow/cadence/runtime" - "github.com/onflow/cadence/runtime/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/onflow/flow-go/fvm/evm" + "github.com/onflow/flow-go/fvm" "github.com/onflow/flow-go/fvm/evm/stdlib" . "github.com/onflow/flow-go/fvm/evm/testutils" "github.com/onflow/flow-go/fvm/evm/types" + "github.com/onflow/flow-go/fvm/storage/snapshot" "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-go/utils/unittest" ) func TestEVMRun(t *testing.T) { @@ -28,19 +28,10 @@ func TestEVMRun(t *testing.T) { RunWithDeployedContract(t, backend, rootAddr, func(testContract *TestContract) { RunWithEOATestAccount(t, backend, rootAddr, func(testAccount *EOATestAccount) { num := int64(12) - - interEnv := runtime.NewBaseInterpreterEnvironment(runtime.Config{}) - - chainID := flow.Emulator - service := chainID.Chain().ServiceAddress() - - err := evm.SetupEnvironment(chainID, backend, interEnv, service) - require.NoError(t, err) - - inter := runtime.NewInterpreterRuntime(runtime.Config{}) - - script := []byte(fmt.Sprintf( - ` + chain := flow.Emulator.Chain() + RunWithNewTestVM(t, chain, func(ctx fvm.Context, vm fvm.VM, snapshot snapshot.SnapshotTree) { + code := []byte(fmt.Sprintf( + ` import EVM from %s access(all) @@ -49,66 +40,72 @@ func TestEVMRun(t *testing.T) { return EVM.run(tx: tx, coinbase: coinbase) } `, - service.HexWithPrefix(), - )) - - gasLimit := uint64(100_000) - - txBytes := testAccount.PrepareSignAndEncodeTx(t, - testContract.DeployedAt.ToCommon(), - testContract.MakeStoreCallData(t, big.NewInt(num)), - big.NewInt(0), - gasLimit, - big.NewInt(1), - ) - - tx := cadence.NewArray( - ConvertToCadence(txBytes), - ).WithType(stdlib.EVMTransactionBytesCadenceType) - - coinbase := cadence.NewArray( - ConvertToCadence(testAccount.Address().Bytes()), - ).WithType(stdlib.EVMAddressBytesCadenceType) - - accountCodes := map[common.Location][]byte{} - var events []cadence.Event - - runtimeInterface := &TestRuntimeInterface{ - Storage: backend, - OnResolveLocation: SingleIdentifierLocationResolver(t), - OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { - accountCodes[location] = code - return nil - }, - OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { - code = accountCodes[location] - return code, nil - }, - OnEmitEvent: func(event cadence.Event) error { - events = append(events, event) - return nil - }, - OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { - return json.Decode(nil, b) - }, - } - - result, err := inter.ExecuteScript( - runtime.Script{ - Source: script, - Arguments: EncodeArgs([]cadence.Value{tx, coinbase}), - }, - runtime.Context{ - Interface: runtimeInterface, - Environment: interEnv, - Location: common.ScriptLocation{}, - }, - ) - require.NoError(t, err) - - assert.Equal(t, cadence.Bool(true), result) + chain.ServiceAddress().HexWithPrefix(), + )) + + gasLimit := uint64(100_000) + + txBytes := testAccount.PrepareSignAndEncodeTx(t, + testContract.DeployedAt.ToCommon(), + testContract.MakeStoreCallData(t, big.NewInt(num)), + big.NewInt(0), + gasLimit, + big.NewInt(1), + ) + + tx := cadence.NewArray( + ConvertToCadence(txBytes), + ).WithType(stdlib.EVMTransactionBytesCadenceType) + + coinbase := cadence.NewArray( + ConvertToCadence(testAccount.Address().Bytes()), + ).WithType(stdlib.EVMAddressBytesCadenceType) + + script := fvm.Script(code).WithArguments( + json.MustEncode(tx), + json.MustEncode(coinbase), + ) + + executionSnapshot, output, err := vm.Run( + ctx, + script, + snapshot) + require.NoError(t, err) + require.NoError(t, output.Err) + assert.Equal(t, cadence.Bool(true), output.Value) + + _ = executionSnapshot + // snapshot = snapshot.Append(executionSnapshot) + }) }) }) }) }) } + +func RunWithNewTestVM(t *testing.T, chain flow.Chain, f func(fvm.Context, fvm.VM, snapshot.SnapshotTree)) { + opts := []fvm.Option{ + fvm.WithChain(chain), + fvm.WithAuthorizationChecksEnabled(false), + fvm.WithSequenceNumberCheckAndIncrementEnabled(false), + fvm.WithEVMEnabled(true), + } + ctx := fvm.NewContext(opts...) + + vm := fvm.NewVirtualMachine() + snapshotTree := snapshot.NewSnapshotTree(nil) + + baseBootstrapOpts := []fvm.BootstrapProcedureOption{ + fvm.WithInitialTokenSupply(unittest.GenesisTokenSupply), + } + + executionSnapshot, _, err := vm.Run( + ctx, + fvm.Bootstrap(unittest.ServiceAccountPublicKey, baseBootstrapOpts...), + snapshotTree) + require.NoError(t, err) + + snapshotTree = snapshotTree.Append(executionSnapshot) + + f(ctx, vm, snapshotTree) +} From 0c63f4f62db3ec7ece4dfd05246098d067930c86 Mon Sep 17 00:00:00 2001 From: ramtinms Date: Thu, 26 Oct 2023 14:21:02 -0700 Subject: [PATCH 2/4] . --- fvm/bootstrap.go | 6 ++++++ fvm/evm/stdlib/contract.go | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/fvm/bootstrap.go b/fvm/bootstrap.go index 8a101b3cd00..c1873d792b8 100644 --- a/fvm/bootstrap.go +++ b/fvm/bootstrap.go @@ -781,6 +781,8 @@ func (b *bootstrapExecutor) setStakingAllowlist( } func (b *bootstrapExecutor) setupEVM(service flow.Address) { + + b.createAccount(nil) // account for storage tx := blueprints.DeployContractTransaction( service, stdlib.ContractCode, @@ -791,6 +793,9 @@ func (b *bootstrapExecutor) setupEVM(service flow.Address) { Transaction(tx, 0), ) panicOnMetaInvokeErrf("failed to deploy EVM contract: %s", txError, err) + // TODO: clean up + // b.accounts.SetContract(stdlib.ContractName, service, stdlib.ContractCode) + // TODO: think about storage } func (b *bootstrapExecutor) registerNodes(service, fungibleToken, flowToken flow.Address) { @@ -989,6 +994,7 @@ func (b *bootstrapExecutor) invokeMetaTransaction( WithAccountStorageLimit(false), WithTransactionFeesEnabled(false), WithAuthorizationChecksEnabled(false), + WithEVMEnabled(true), WithSequenceNumberCheckAndIncrementEnabled(false), // disable interaction and computation limits for bootstrapping diff --git a/fvm/evm/stdlib/contract.go b/fvm/evm/stdlib/contract.go index f8277a19cc5..c98b221cc30 100644 --- a/fvm/evm/stdlib/contract.go +++ b/fvm/evm/stdlib/contract.go @@ -341,10 +341,22 @@ func newInternalEVMStandardLibraryValue( } } +func newInternalEVMStandardLibraryType() stdlib.StandardLibraryType { + return stdlib.StandardLibraryType{ + Name: InternalEVMContractName, + Type: InternalEVMContractType, + Kind: common.DeclarationKindContract, + } +} + func SetupEnvironment(env runtime.Environment, handler types.ContractHandler, service flow.Address) { + location := common.NewAddressLocation(nil, common.Address(service), ContractName) + env.DeclareType( + newInternalEVMStandardLibraryType(), + location) env.DeclareValue( newInternalEVMStandardLibraryValue(nil, handler), - common.NewAddressLocation(nil, common.Address(service), ContractName), + location, ) } From 97bf847115198230f91b5e9a9405237dc12b4019 Mon Sep 17 00:00:00 2001 From: ramtinms Date: Thu, 26 Oct 2023 14:33:25 -0700 Subject: [PATCH 3/4] . --- fvm/evm/evm_test.go | 2 +- fvm/evm/handler/handler.go | 4 +++- fvm/evm/testutils/accounts.go | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/fvm/evm/evm_test.go b/fvm/evm/evm_test.go index 68e7cef31cd..5fe1069453d 100644 --- a/fvm/evm/evm_test.go +++ b/fvm/evm/evm_test.go @@ -50,7 +50,7 @@ func TestEVMRun(t *testing.T) { testContract.MakeStoreCallData(t, big.NewInt(num)), big.NewInt(0), gasLimit, - big.NewInt(1), + big.NewInt(0), ) tx := cadence.NewArray( diff --git a/fvm/evm/handler/handler.go b/fvm/evm/handler/handler.go index a7569919f98..f8224c47d22 100644 --- a/fvm/evm/handler/handler.go +++ b/fvm/evm/handler/handler.go @@ -136,7 +136,9 @@ func (h ContractHandler) Run(rlpEncodedTx []byte, coinbase types.Address) bool { } if res == nil { // fatal error - panic("empty result is retuned by emulator") + // TODO: fix me, Temp work around for now. + res = &types.Result{} + // panic("empty result is retuned by emulator") } res.Failed = failed diff --git a/fvm/evm/testutils/accounts.go b/fvm/evm/testutils/accounts.go index c1453ac1ef8..2e21c8ad000 100644 --- a/fvm/evm/testutils/accounts.go +++ b/fvm/evm/testutils/accounts.go @@ -106,5 +106,12 @@ func RunWithEOATestAccount(t *testing.T, led atree.Ledger, flowEVMRootAddress fl _, err = blk.MintTo(account.Address(), new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1000))) require.NoError(t, err) + blk2, err := e.NewReadOnlyBlockView(types.NewDefaultBlockContext(2)) + require.NoError(t, err) + + bal, err := blk2.BalanceOf(account.Address()) + require.NoError(t, err) + require.Greater(t, bal.Uint64(), uint64(0)) + f(account) } From df97aa0673c8f1ea1362053ce40d194c77bcea4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 26 Oct 2023 16:12:52 -0700 Subject: [PATCH 4/4] refactor to variable --- fvm/evm/evm_test.go | 1 + fvm/evm/stdlib/contract.go | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fvm/evm/evm_test.go b/fvm/evm/evm_test.go index 5fe1069453d..0a9a3bf1893 100644 --- a/fvm/evm/evm_test.go +++ b/fvm/evm/evm_test.go @@ -13,6 +13,7 @@ import ( "github.com/onflow/flow-go/fvm" "github.com/onflow/flow-go/fvm/evm/stdlib" . "github.com/onflow/flow-go/fvm/evm/testutils" + "github.com/onflow/flow-go/fvm/evm/types" "github.com/onflow/flow-go/fvm/storage/snapshot" "github.com/onflow/flow-go/model/flow" diff --git a/fvm/evm/stdlib/contract.go b/fvm/evm/stdlib/contract.go index c98b221cc30..4339c682923 100644 --- a/fvm/evm/stdlib/contract.go +++ b/fvm/evm/stdlib/contract.go @@ -341,19 +341,18 @@ func newInternalEVMStandardLibraryValue( } } -func newInternalEVMStandardLibraryType() stdlib.StandardLibraryType { - return stdlib.StandardLibraryType{ - Name: InternalEVMContractName, - Type: InternalEVMContractType, - Kind: common.DeclarationKindContract, - } +var internalEVMStandardLibraryType = stdlib.StandardLibraryType{ + Name: InternalEVMContractName, + Type: InternalEVMContractType, + Kind: common.DeclarationKindContract, } func SetupEnvironment(env runtime.Environment, handler types.ContractHandler, service flow.Address) { location := common.NewAddressLocation(nil, common.Address(service), ContractName) env.DeclareType( - newInternalEVMStandardLibraryType(), - location) + internalEVMStandardLibraryType, + location, + ) env.DeclareValue( newInternalEVMStandardLibraryValue(nil, handler), location,