From b59d9a23ea226ca979ed8b2f2e1b2cf30364b645 Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 17 Sep 2021 23:23:51 +0800 Subject: [PATCH] evm: add `ApplyNativeMessage` (#557) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add ApplyNativeMessage Closes #533 * fix lint * Update x/evm/types/tracer.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * Update x/evm/types/tracer.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * no-op tracer Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze --- app/ante/eth.go | 2 +- x/evm/keeper/state_transition.go | 32 ++++++++++++++++++++++++++++++++ x/evm/types/tracer.go | 29 ++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/app/ante/eth.go b/app/ante/eth.go index 6043f0e4f..ce429a138 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -362,7 +362,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate } // NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below - evm := ctd.evmKeeper.NewEVM(coreMsg, ethCfg, params, common.Address{}, nil) + evm := ctd.evmKeeper.NewEVM(coreMsg, ethCfg, params, common.Address{}, evmtypes.NewNoOpTracer()) // check that caller has enough balance to cover asset transfer for **topmost** call // NOTE: here the gas consumed is from the context with the infinite gas meter diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index be77ad58b..422f7f130 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -311,6 +311,38 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message, cfg *params.ChainCo }, nil } +// ApplyNativeMessage executes an ethereum message on the EVM. It is meant to be called from an internal +// native Cosmos SDK module. +func (k *Keeper) ApplyNativeMessage(msg core.Message) (*types.MsgEthereumTxResponse, error) { + // TODO: clean up and remove duplicate code. + + ctx := k.Ctx() + params := k.GetParams(ctx) + // return error if contract creation or call are disabled through governance + if !params.EnableCreate && msg.To() == nil { + return nil, stacktrace.Propagate(types.ErrCreateDisabled, "failed to create new contract") + } else if !params.EnableCall && msg.To() != nil { + return nil, stacktrace.Propagate(types.ErrCallDisabled, "failed to call contract") + } + + ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID) + + // get the coinbase address from the block proposer + coinbase, err := k.GetCoinbaseAddress(ctx) + if err != nil { + return nil, stacktrace.Propagate(err, "failed to obtain coinbase address") + } + + evm := k.NewEVM(msg, ethCfg, params, coinbase, nil) + + ret, err := k.ApplyMessage(evm, msg, ethCfg, true) + if err != nil { + return nil, err + } + k.CommitCachedContexts() + return ret, nil +} + // GetEthIntrinsicGas returns the intrinsic gas cost for the transaction func (k *Keeper) GetEthIntrinsicGas(msg core.Message, cfg *params.ChainConfig, isContractCreation bool) (uint64, error) { height := big.NewInt(k.Ctx().BlockHeight()) diff --git a/x/evm/types/tracer.go b/x/evm/types/tracer.go index b61932caa..1041139b9 100644 --- a/x/evm/types/tracer.go +++ b/x/evm/types/tracer.go @@ -4,7 +4,9 @@ import ( "fmt" "math/big" "os" + "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" @@ -36,7 +38,7 @@ func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height case TracerStruct: return vm.NewStructLogger(logCfg) default: - return nil + return NewNoOpTracer() } } @@ -112,3 +114,28 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes { } return formatted } + +var _ vm.Tracer = &NoOpTracer{} + +// NoOpTracer is an empty implementation of vm.Tracer interface +type NoOpTracer struct{} + +// NewNoOpTracer creates a no-op vm.Tracer +func NewNoOpTracer() *NoOpTracer { + return &NoOpTracer{} +} + +// CaptureStart implements vm.Tracer interface +func (dt NoOpTracer) CaptureStart(env *vm.EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { +} + +// CaptureState implements vm.Tracer interface +func (dt NoOpTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +} + +// CaptureFault implements vm.Tracer interface +func (dt NoOpTracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +} + +// CaptureEnd implements vm.Tracer interface +func (dt NoOpTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {}