From 7d896c68cb002d3df05f9f7ab3957d9899dae58b Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 30 Nov 2023 14:34:51 +0100 Subject: [PATCH 01/11] add evm event location --- fvm/evm/types/events.go | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/fvm/evm/types/events.go b/fvm/evm/types/events.go index 18fe04d26df..11cc4fb6375 100644 --- a/fvm/evm/types/events.go +++ b/fvm/evm/types/events.go @@ -2,6 +2,11 @@ package types import ( "encoding/hex" + "encoding/json" + "fmt" + "strings" + + "github.com/onflow/cadence/runtime/common" gethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" @@ -26,6 +31,52 @@ type Event struct { Payload EventPayload } +type EVMLocation struct{} + +var _ common.Location = EVMLocation{} + +const ( + evmLocationPrefix = "evm" + locationDivider = "." +) + +func (l EVMLocation) TypeID(memoryGauge common.MemoryGauge, qualifiedIdentifier string) common.TypeID { + id := fmt.Sprintf("%s.%s", locationDivider, qualifiedIdentifier) + common.UseMemory(memoryGauge, common.NewRawStringMemoryUsage(len(id))) + + return common.TypeID(id) +} + +func (l EVMLocation) QualifiedIdentifier(typeID common.TypeID) string { + pieces := strings.SplitN(string(typeID), locationDivider, 2) + + if len(pieces) < 2 { + return "" + } + + return pieces[1] +} + +func (l EVMLocation) String() string { + return evmLocationPrefix +} + +func (l EVMLocation) Description() string { + return evmLocationPrefix +} + +func (l EVMLocation) ID() string { + return evmLocationPrefix +} + +func (l EVMLocation) MarshalJSON() ([]byte, error) { + return json.Marshal(&struct { + Type string + }{ + Type: "EVMLocation", + }) +} + // we might break this event into two (tx included /tx executed) if size becomes an issue type TransactionExecutedPayload struct { BlockHeight uint64 From c0229675c6c0a36e8bb43b2ecc0bf6b67a4acd8e Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 30 Nov 2023 14:37:50 +0100 Subject: [PATCH 02/11] add evm location type to event --- fvm/evm/types/events.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/fvm/evm/types/events.go b/fvm/evm/types/events.go index 11cc4fb6375..01a055c0ad0 100644 --- a/fvm/evm/types/events.go +++ b/fvm/evm/types/events.go @@ -11,14 +11,14 @@ import ( gethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" "github.com/onflow/cadence" - "github.com/onflow/cadence/runtime/stdlib" - "github.com/onflow/flow-go/model/flow" ) const ( EventTypeBlockExecuted flow.EventType = "evm.BlockExecuted" EventTypeTransactionExecuted flow.EventType = "evm.TransactionExecuted" + evmLocationPrefix = "evm" + locationDivider = "." ) type EventPayload interface { @@ -31,14 +31,9 @@ type Event struct { Payload EventPayload } -type EVMLocation struct{} - var _ common.Location = EVMLocation{} -const ( - evmLocationPrefix = "evm" - locationDivider = "." -) +type EVMLocation struct{} func (l EVMLocation) TypeID(memoryGauge common.MemoryGauge, qualifiedIdentifier string) common.TypeID { id := fmt.Sprintf("%s.%s", locationDivider, qualifiedIdentifier) @@ -97,7 +92,7 @@ func (p *TransactionExecutedPayload) CadenceEvent() (cadence.Event, error) { return cadence.Event{ EventType: cadence.NewEventType( - stdlib.FlowLocation{}, + EVMLocation{}, string(EventTypeTransactionExecuted), []cadence.Field{ cadence.NewField("blockHeight", cadence.UInt64Type{}), @@ -164,7 +159,7 @@ func (p *BlockExecutedEventPayload) CadenceEvent() (cadence.Event, error) { cadence.String(p.Block.StateRoot.String()), cadence.NewArray(hashes).WithType(hashesType), }).WithType(&cadence.EventType{ - Location: stdlib.FlowLocation{}, // todo create evm custom location + Location: EVMLocation{}, QualifiedIdentifier: string(EventTypeBlockExecuted), Fields: []cadence.Field{ cadence.NewField("height", cadence.UInt64Type{}), From 52239fb036c1fc41741e5e615d836ba780f7c7c3 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 30 Nov 2023 16:26:05 +0100 Subject: [PATCH 03/11] add parser for event type --- fvm/evm/types/events.go | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/fvm/evm/types/events.go b/fvm/evm/types/events.go index 01a055c0ad0..77c0469e27b 100644 --- a/fvm/evm/types/events.go +++ b/fvm/evm/types/events.go @@ -15,8 +15,8 @@ import ( ) const ( - EventTypeBlockExecuted flow.EventType = "evm.BlockExecuted" - EventTypeTransactionExecuted flow.EventType = "evm.TransactionExecuted" + EventTypeBlockExecuted flow.EventType = "BlockExecuted" + EventTypeTransactionExecuted flow.EventType = "TransactionExecuted" evmLocationPrefix = "evm" locationDivider = "." ) @@ -36,7 +36,7 @@ var _ common.Location = EVMLocation{} type EVMLocation struct{} func (l EVMLocation) TypeID(memoryGauge common.MemoryGauge, qualifiedIdentifier string) common.TypeID { - id := fmt.Sprintf("%s.%s", locationDivider, qualifiedIdentifier) + id := fmt.Sprintf("%s%s%s", evmLocationPrefix, locationDivider, qualifiedIdentifier) common.UseMemory(memoryGauge, common.NewRawStringMemoryUsage(len(id))) return common.TypeID(id) @@ -72,6 +72,31 @@ func (l EVMLocation) MarshalJSON() ([]byte, error) { }) } +func init() { + common.RegisterTypeIDDecoder( + evmLocationPrefix, + func(_ common.MemoryGauge, typeID string) (common.Location, string, error) { + if typeID == "" { + return nil, "", fmt.Errorf("invalid EVM type location ID: missing type prefix") + } + + parts := strings.SplitN(typeID, ".", 2) + prefix := parts[0] + if prefix != evmLocationPrefix { + return EVMLocation{}, "", fmt.Errorf("invalid EVM type location ID: invalid prefix") + } + + var qualifiedIdentifier string + pieceCount := len(parts) + if pieceCount > 1 { + qualifiedIdentifier = parts[1] + } + + return EVMLocation{}, qualifiedIdentifier, nil + }, + ) +} + // we might break this event into two (tx included /tx executed) if size becomes an issue type TransactionExecutedPayload struct { BlockHeight uint64 From 11005c3df9886322cf21c3df102a5a08b7b2b322 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 10 Jan 2024 18:11:54 +0100 Subject: [PATCH 04/11] remove proofs and reorder --- fvm/evm/types/events.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fvm/evm/types/events.go b/fvm/evm/types/events.go index 7084f7954b6..e105c4ff158 100644 --- a/fvm/evm/types/events.go +++ b/fvm/evm/types/events.go @@ -6,11 +6,11 @@ import ( "fmt" "strings" - "github.com/onflow/cadence/runtime/common" - gethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" "github.com/onflow/cadence" + "github.com/onflow/cadence/runtime/common" + "github.com/onflow/flow-go/model/flow" ) @@ -117,7 +117,7 @@ func (p *TransactionExecutedPayload) CadenceEvent() (cadence.Event, error) { return cadence.Event{ EventType: cadence.NewEventType( - stdlib.FlowLocation{}, + EVMLocation{}, string(EventTypeTransactionExecuted), []cadence.Field{ cadence.NewField("blockHeight", cadence.UInt64Type{}), @@ -126,7 +126,6 @@ func (p *TransactionExecutedPayload) CadenceEvent() (cadence.Event, error) { cadence.NewField("failed", cadence.BoolType{}), cadence.NewField("transactionType", cadence.UInt8Type{}), cadence.NewField("gasConsumed", cadence.UInt64Type{}), - cadence.NewField("stateRootHash", cadence.StringType{}), cadence.NewField("deployedContractAddress", cadence.StringType{}), cadence.NewField("returnedValue", cadence.StringType{}), cadence.NewField("logs", cadence.StringType{}), @@ -140,7 +139,6 @@ func (p *TransactionExecutedPayload) CadenceEvent() (cadence.Event, error) { cadence.NewBool(p.Result.Failed), cadence.NewUInt8(p.Result.TxType), cadence.NewUInt64(p.Result.GasConsumed), - cadence.String(p.Result.StateRootHash.String()), cadence.String(hex.EncodeToString(p.Result.DeployedContractAddress.Bytes())), cadence.String(hex.EncodeToString(p.Result.ReturnedValue)), cadence.String(hex.EncodeToString(encodedLogs)), @@ -166,7 +164,7 @@ func NewTransactionExecutedEvent( } var blockExecutedEventCadenceType = &cadence.EventType{ - Location: stdlib.FlowLocation{}, // todo create evm custom location + Location: EVMLocation{}, QualifiedIdentifier: string(EventTypeBlockExecuted), Fields: []cadence.Field{ cadence.NewField("height", cadence.UInt64Type{}), @@ -193,8 +191,8 @@ func (p *BlockExecutedEventPayload) CadenceEvent() (cadence.Event, error) { fields := []cadence.Value{ cadence.NewUInt64(p.Block.Height), cadence.NewUInt64(p.Block.TotalSupply), - cadence.String(p.Block.ReceiptRoot.String()), cadence.String(p.Block.ParentBlockHash.String()), + cadence.String(p.Block.ReceiptRoot.String()), cadence.NewArray(hashes).WithType(cadence.NewVariableSizedArrayType(cadence.StringType{})), } From 29d5c71d61de243b16334818e4fee82b8049f6a9 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 11 Jan 2024 13:46:38 +0100 Subject: [PATCH 05/11] add test for transaction events --- fvm/fvm_test.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index 4017ec1f638..8191e75f786 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -8,8 +8,6 @@ import ( "strings" "testing" - "github.com/onflow/flow-go/fvm/evm/stdlib" - "github.com/onflow/cadence" "github.com/onflow/cadence/encoding/ccf" jsoncdc "github.com/onflow/cadence/encoding/json" @@ -19,13 +17,13 @@ import ( "github.com/stretchr/testify/require" "github.com/onflow/flow-go/crypto" - "github.com/onflow/flow-go/engine/execution/testutil" exeUtils "github.com/onflow/flow-go/engine/execution/utils" "github.com/onflow/flow-go/fvm" fvmCrypto "github.com/onflow/flow-go/fvm/crypto" "github.com/onflow/flow-go/fvm/environment" errors "github.com/onflow/flow-go/fvm/errors" + "github.com/onflow/flow-go/fvm/evm/stdlib" "github.com/onflow/flow-go/fvm/meter" reusableRuntime "github.com/onflow/flow-go/fvm/runtime" "github.com/onflow/flow-go/fvm/storage/snapshot" @@ -3013,4 +3011,55 @@ func TestEVM(t *testing.T) { )) }), ) + + t.Run("deploy contract code", newVMTest(). + withBootstrapProcedureOptions(fvm.WithSetupEVMEnabled(true)). + // we keep this dissabled during bootstrap and later overwrite in the test for test transaction + withContextOptions( + fvm.WithEVMEnabled(false), + fvm.WithCadenceLogging(true), + ). + run(func( + t *testing.T, + vm fvm.VM, + chain flow.Chain, + ctx fvm.Context, + snapshotTree snapshot.SnapshotTree, + ) { + + txBody := flow.NewTransactionBody(). + SetScript([]byte(fmt.Sprintf(` + import FungibleToken from 0x%s + import FlowToken from 0x%s + import EVM from %s + + transaction() { + prepare(acc: AuthAccount) { + let vaultRef = acc.borrow<&{FungibleToken.Provider}>(from: /storage/flowTokenVault) + ?? panic("Could not borrow reference to the owner''s Vault!") + + let acc <- EVM.createBridgedAccount() + acc.deposit(from: <- vaultRef.withdraw(amount: 0.0000001)) + destroy acc + } + } + `, chain.ServiceAddress().HexWithPrefix()))). + SetProposalKey(chain.ServiceAddress(), 0, 0). + AddAuthorizer(chain.ServiceAddress()). + SetPayer(chain.ServiceAddress()) + + err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain) + require.NoError(t, err) + + ctx = fvm.NewContextFromParent(ctx, fvm.WithEVMEnabled(true)) + _, output, err := vm.Run( + ctx, + fvm.Transaction(txBody, 0), + snapshotTree) + + require.NoError(t, err) + require.NoError(t, output.Err) + require.Len(t, output.Logs, 1) + }), + ) } From 51a4b591f7cb8b67161173b2905b17984d77cc4e Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 11 Jan 2024 15:15:29 +0100 Subject: [PATCH 06/11] import lint --- fvm/fvm_test.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index 8191e75f786..33e7c145bd8 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -14,6 +14,7 @@ import ( "github.com/onflow/cadence/runtime" "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/tests/utils" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/onflow/flow-go/crypto" @@ -24,6 +25,7 @@ import ( "github.com/onflow/flow-go/fvm/environment" errors "github.com/onflow/flow-go/fvm/errors" "github.com/onflow/flow-go/fvm/evm/stdlib" + "github.com/onflow/flow-go/fvm/evm/types" "github.com/onflow/flow-go/fvm/meter" reusableRuntime "github.com/onflow/flow-go/fvm/runtime" "github.com/onflow/flow-go/fvm/storage/snapshot" @@ -3026,11 +3028,12 @@ func TestEVM(t *testing.T) { ctx fvm.Context, snapshotTree snapshot.SnapshotTree, ) { + sc := systemcontracts.SystemContractsForChain(chain.ChainID()) txBody := flow.NewTransactionBody(). SetScript([]byte(fmt.Sprintf(` - import FungibleToken from 0x%s - import FlowToken from 0x%s + import FungibleToken from %s + import FlowToken from %s import EVM from %s transaction() { @@ -3039,11 +3042,15 @@ func TestEVM(t *testing.T) { ?? panic("Could not borrow reference to the owner''s Vault!") let acc <- EVM.createBridgedAccount() - acc.deposit(from: <- vaultRef.withdraw(amount: 0.0000001)) + let amount <- vaultRef.withdraw(amount: 0.0000001) as! @FlowToken.Vault + acc.deposit(from: <- amount) destroy acc } - } - `, chain.ServiceAddress().HexWithPrefix()))). + }`, + sc.FungibleToken.Address.HexWithPrefix(), + sc.FlowToken.Address.HexWithPrefix(), + sc.FlowServiceAccount.Address.HexWithPrefix(), // TODO this should be sc.EVM.Address not found there??? + ))). SetProposalKey(chain.ServiceAddress(), 0, 0). AddAuthorizer(chain.ServiceAddress()). SetPayer(chain.ServiceAddress()) @@ -3059,7 +3066,11 @@ func TestEVM(t *testing.T) { require.NoError(t, err) require.NoError(t, output.Err) - require.Len(t, output.Logs, 1) + require.Len(t, output.Events, 3) + + txExe, blockExe := output.Events[1], output.Events[2] + assert.Equal(t, types.EVMLocation{}.TypeID(nil, string(types.EventTypeTransactionExecuted)), common.TypeID(txExe.Type)) + assert.Equal(t, types.EVMLocation{}.TypeID(nil, string(types.EventTypeBlockExecuted)), common.TypeID(blockExe.Type)) }), ) } From 1a02a245ae2dd09c229d74aab95f2e5fc4166caa Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 11 Jan 2024 15:17:49 +0100 Subject: [PATCH 07/11] check for correct events emitted --- fvm/fvm_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index 33e7c145bd8..0cbdf317660 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -3068,9 +3068,10 @@ func TestEVM(t *testing.T) { require.NoError(t, output.Err) require.Len(t, output.Events, 3) + evmLocation := types.EVMLocation{} txExe, blockExe := output.Events[1], output.Events[2] - assert.Equal(t, types.EVMLocation{}.TypeID(nil, string(types.EventTypeTransactionExecuted)), common.TypeID(txExe.Type)) - assert.Equal(t, types.EVMLocation{}.TypeID(nil, string(types.EventTypeBlockExecuted)), common.TypeID(blockExe.Type)) + assert.Equal(t, evmLocation.TypeID(nil, string(types.EventTypeTransactionExecuted)), common.TypeID(txExe.Type)) + assert.Equal(t, evmLocation.TypeID(nil, string(types.EventTypeBlockExecuted)), common.TypeID(blockExe.Type)) }), ) } From 6aa6434fb5fa3423630fce78f330cd9d1ad21144 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 11 Jan 2024 15:49:18 +0100 Subject: [PATCH 08/11] fix typo --- fvm/fvm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index 0cbdf317660..f7fa5858c15 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -3039,7 +3039,7 @@ func TestEVM(t *testing.T) { transaction() { prepare(acc: AuthAccount) { let vaultRef = acc.borrow<&{FungibleToken.Provider}>(from: /storage/flowTokenVault) - ?? panic("Could not borrow reference to the owner''s Vault!") + ?? panic("Could not borrow reference to the owner's Vault!") let acc <- EVM.createBridgedAccount() let amount <- vaultRef.withdraw(amount: 0.0000001) as! @FlowToken.Vault From b633a9cec292a4c3caf01e9e8dfdc9be5eb4f5db Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 12 Jan 2024 19:23:16 +0100 Subject: [PATCH 09/11] fix unneeded test call --- fvm/fvm_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index f7fa5858c15..671e58c2cfb 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -3016,11 +3016,6 @@ func TestEVM(t *testing.T) { t.Run("deploy contract code", newVMTest(). withBootstrapProcedureOptions(fvm.WithSetupEVMEnabled(true)). - // we keep this dissabled during bootstrap and later overwrite in the test for test transaction - withContextOptions( - fvm.WithEVMEnabled(false), - fvm.WithCadenceLogging(true), - ). run(func( t *testing.T, vm fvm.VM, From 1ab6284e8d24318e7ebd2a139064a0e1d727379f Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 12 Jan 2024 19:27:12 +0100 Subject: [PATCH 10/11] update master --- fvm/fvm_test.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index 7651ef82ee0..b34b68fd606 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -28,8 +28,6 @@ import ( "github.com/onflow/flow-go/fvm/errors" "github.com/onflow/flow-go/fvm/evm/stdlib" "github.com/onflow/flow-go/fvm/evm/types" - "github.com/onflow/flow-go/fvm/evm/stdlib" - "github.com/onflow/flow-go/fvm/evm/types" "github.com/onflow/flow-go/fvm/meter" reusableRuntime "github.com/onflow/flow-go/fvm/runtime" "github.com/onflow/flow-go/fvm/storage/snapshot" @@ -2963,11 +2961,7 @@ func TestEVM(t *testing.T) { t.Run("successful transaction", newVMTest(). withBootstrapProcedureOptions(fvm.WithSetupEVMEnabled(true)). - // we keep this dissabled during bootstrap and later overwrite in the test for test transaction - withContextOptions( - fvm.WithEVMEnabled(false), - fvm.WithCadenceLogging(true), - ). + withContextOptions(fvm.WithCadenceLogging(true)). run(func( t *testing.T, vm fvm.VM, @@ -3022,7 +3016,6 @@ func TestEVM(t *testing.T) { // this test makes sure the execution error is correctly handled and returned as a correct type t.Run("execution reverted", newVMTest(). withBootstrapProcedureOptions(fvm.WithSetupEVMEnabled(true)). - withContextOptions(fvm.WithEVMEnabled(true)). run(func( t *testing.T, vm fvm.VM, @@ -3058,7 +3051,6 @@ func TestEVM(t *testing.T) { // we have implemented a snapshot wrapper to return an error from the EVM t.Run("internal evm error handling", newVMTest(). withBootstrapProcedureOptions(fvm.WithSetupEVMEnabled(true)). - withContextOptions(fvm.WithEVMEnabled(true)). run(func( t *testing.T, vm fvm.VM, From f062c463d405b27de5ffc78c35c1c716ad569cd4 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 12 Jan 2024 19:27:59 +0100 Subject: [PATCH 11/11] update master --- fvm/fvm_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index b34b68fd606..ebcf3404a57 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -3016,6 +3016,7 @@ func TestEVM(t *testing.T) { // this test makes sure the execution error is correctly handled and returned as a correct type t.Run("execution reverted", newVMTest(). withBootstrapProcedureOptions(fvm.WithSetupEVMEnabled(true)). + withContextOptions(fvm.WithEVMEnabled(true)). run(func( t *testing.T, vm fvm.VM, @@ -3051,6 +3052,7 @@ func TestEVM(t *testing.T) { // we have implemented a snapshot wrapper to return an error from the EVM t.Run("internal evm error handling", newVMTest(). withBootstrapProcedureOptions(fvm.WithSetupEVMEnabled(true)). + withContextOptions(fvm.WithEVMEnabled(true)). run(func( t *testing.T, vm fvm.VM,