From b5ad3c51bb0551b581ea985d1e804c0035a92673 Mon Sep 17 00:00:00 2001 From: Freddy Caceres Date: Thu, 21 Mar 2024 08:57:23 -0400 Subject: [PATCH 1/6] imp(evm): PreExecuteCallback for Call opcodes --- core/vm/contracts.go | 4 +++ core/vm/evm.go | 70 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 64b335db74a3..ee433ce21956 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -203,6 +203,10 @@ func (evm *EVM) Precompile(addr common.Address) (PrecompiledContract, bool) { return p, ok } +func (evm *EVM) GetPrecompiles() ([]common.Address, map[common.Address]PrecompiledContract) { + return evm.activePrecompiles, evm.precompiles +} + // WithPrecompiles sets the precompiled contracts and the slice of actives precompiles. // IMPORTANT: This function does NOT validate the precompiles provided to the EVM. The caller should // use the ValidatePrecompiles function for this purpose prior to calling WithPrecompiles. diff --git a/core/vm/evm.go b/core/vm/evm.go index 5d0ea1a2c311..c169f1417d9b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -109,18 +109,49 @@ type EVM struct { precompiles map[common.Address]PrecompiledContract // activePrecompiles defines the precompiles that are currently active activePrecompiles []common.Address + + // preExecuteCallback is a callback function that is called before executing + // CALL, CALLCODE, DELEGATECALL and STATICCALL opcodes. + preExecuteCallback preExecuteCallbackType +} + +type preExecuteCallbackType func(evm *EVM, addr common.Address) error + +func dummyCallback(evm *EVM, addr common.Address) error { + return nil } // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { evm := &EVM{ - Context: blockCtx, - TxContext: txCtx, - StateDB: statedb, - Config: config, - chainConfig: chainConfig, - chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), + Context: blockCtx, + TxContext: txCtx, + StateDB: statedb, + Config: config, + chainConfig: chainConfig, + chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), + preExecuteCallback: dummyCallback, + } + // set the default precompiles + evm.activePrecompiles = DefaultActivePrecompiles(evm.chainRules) + evm.precompiles = DefaultPrecompiles(evm.chainRules) + evm.interpreter = NewEVMInterpreter(evm, config) + + return evm +} + +// NewEVM returns a new EVM. The returned EVM is not thread safe and should +// only ever be used *once*. +func NewEVM2(callback preExecuteCallbackType, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { + evm := &EVM{ + Context: blockCtx, + TxContext: txCtx, + StateDB: statedb, + Config: config, + chainConfig: chainConfig, + chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), + preExecuteCallback: callback, } // set the default precompiles evm.activePrecompiles = DefaultActivePrecompiles(evm.chainRules) @@ -158,11 +189,22 @@ func (evm *EVM) WithInterpreter(interpreter Interpreter) { evm.interpreter = interpreter } +type callBack func(addr common.Address, evm *EVM) error + +type ExtensionCaller interface { + ContractRef +} + // Call executes the contract associated with the addr with the given input as // parameters. It also handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { + err = evm.preExecuteCallback(evm, addr) + if err != nil { + return nil, gas, err + } + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -171,6 +213,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, ErrInsufficientBalance } + snapshot := evm.StateDB.Snapshot() p, isPrecompile := evm.Precompile(addr) @@ -250,6 +293,11 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { + err = evm.preExecuteCallback(evm, addr) + if err != nil { + return nil, gas, err + } + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -298,6 +346,11 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + err = evm.preExecuteCallback(evm, addr) + if err != nil { + return nil, gas, err + } + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -337,6 +390,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + err = evm.preExecuteCallback(evm, addr) + if err != nil { + return nil, gas, err + } + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth From b396857715ae2eb6a9772e195604db675801607b Mon Sep 17 00:00:00 2001 From: Freddy Caceres Date: Thu, 21 Mar 2024 09:01:28 -0400 Subject: [PATCH 2/6] remove getter function --- core/vm/contracts.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index ee433ce21956..64b335db74a3 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -203,10 +203,6 @@ func (evm *EVM) Precompile(addr common.Address) (PrecompiledContract, bool) { return p, ok } -func (evm *EVM) GetPrecompiles() ([]common.Address, map[common.Address]PrecompiledContract) { - return evm.activePrecompiles, evm.precompiles -} - // WithPrecompiles sets the precompiled contracts and the slice of actives precompiles. // IMPORTANT: This function does NOT validate the precompiles provided to the EVM. The caller should // use the ValidatePrecompiles function for this purpose prior to calling WithPrecompiles. From b60d436ce5942e36c7050be1e3e9f31c27428522 Mon Sep 17 00:00:00 2001 From: Freddy Caceres Date: Thu, 21 Mar 2024 09:47:37 -0400 Subject: [PATCH 3/6] remove unnecessary code --- core/vm/evm.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index c169f1417d9b..6b90ad5d1779 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -143,7 +143,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM2(callback preExecuteCallbackType, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { +func NewEVM2(callBack preExecuteCallbackType, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { evm := &EVM{ Context: blockCtx, TxContext: txCtx, @@ -151,7 +151,7 @@ func NewEVM2(callback preExecuteCallbackType, blockCtx BlockContext, txCtx TxCon Config: config, chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), - preExecuteCallback: callback, + preExecuteCallback: callBack, } // set the default precompiles evm.activePrecompiles = DefaultActivePrecompiles(evm.chainRules) @@ -189,12 +189,6 @@ func (evm *EVM) WithInterpreter(interpreter Interpreter) { evm.interpreter = interpreter } -type callBack func(addr common.Address, evm *EVM) error - -type ExtensionCaller interface { - ContractRef -} - // Call executes the contract associated with the addr with the given input as // parameters. It also handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an From 7fe0647808eac8cca1cc52e76b0e4cf705926086 Mon Sep 17 00:00:00 2001 From: Freddy Caceres Date: Thu, 21 Mar 2024 09:49:15 -0400 Subject: [PATCH 4/6] fix naming typo --- core/vm/evm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 6b90ad5d1779..2689fd5344a0 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -143,7 +143,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM2(callBack preExecuteCallbackType, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { +func NewEVM2(callback preExecuteCallbackType, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { evm := &EVM{ Context: blockCtx, TxContext: txCtx, @@ -151,7 +151,7 @@ func NewEVM2(callBack preExecuteCallbackType, blockCtx BlockContext, txCtx TxCon Config: config, chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), - preExecuteCallback: callBack, + preExecuteCallback: callback, } // set the default precompiles evm.activePrecompiles = DefaultActivePrecompiles(evm.chainRules) From 02a4aae5e00111c01db4ff00e05545e98e143729 Mon Sep 17 00:00:00 2001 From: Freddy Caceres Date: Thu, 21 Mar 2024 10:02:04 -0400 Subject: [PATCH 5/6] rename function --- core/vm/evm.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 2689fd5344a0..f58a08d960f4 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -141,9 +141,9 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig return evm } -// NewEVM returns a new EVM. The returned EVM is not thread safe and should -// only ever be used *once*. -func NewEVM2(callback preExecuteCallbackType, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { +// NewEVMWithCallback returns a new EVM and takes a custom preExecuteCallback. The returned EVM is +// not thread safe and should only ever be used *once*. +func NewEVMWithCallback(callback preExecuteCallbackType, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { evm := &EVM{ Context: blockCtx, TxContext: txCtx, From 875349f99c898e447fcf5751a3b81b87d2a5e18a Mon Sep 17 00:00:00 2001 From: tom Date: Wed, 10 Apr 2024 12:12:24 -0300 Subject: [PATCH 6/6] add lic --- core/vm/evm.go | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index f58a08d960f4..baa349422504 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -1,18 +1,5 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) package vm