diff --git a/core/vm/evm.go b/core/vm/evm.go index 5d0ea1a2c311..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 @@ -109,18 +96,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 +} + +// 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, + 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) @@ -163,6 +181,11 @@ func (evm *EVM) WithInterpreter(interpreter Interpreter) { // 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 +194,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 +274,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 +327,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 +371,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