diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index fe12a1a8c3..d599dd38c9 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -386,7 +386,7 @@ func (k *Keeper) ApplyMessageWithConfig( ret, _, leftoverGas, vmErr = nEVM.Create(sender, msg.Data(), leftoverGas, msg.Value()) stateDB.SetNonce(sender.Address(), msg.Nonce()+1) } else { - ret, leftoverGas, vmErr = nEVM.Call(sender, *msg.To(), msg.Data(), leftoverGas, msg.Value()) + ret, leftoverGas, vmErr = nEVM.Call(sender, *msg.To(), msg.Data(), leftoverGas, msg.Value(), commit) } refundQuotient := params.RefundQuotient diff --git a/x/evm/vm/geth/geth.go b/x/evm/vm/geth/geth.go index 1222551ea6..834da70727 100644 --- a/x/evm/vm/geth/geth.go +++ b/x/evm/vm/geth/geth.go @@ -105,11 +105,29 @@ func (e *EVM) RunStatefulPrecompiledContract( return output, suppliedGas, err } +// PreRunStatefulPrecompiledContract runs a stateful precompiled contract and ignores the address and +// value arguments. It uses the RunPrecompiledContract function from the geth vm package +func (e *EVM) PreRunStatefulPrecompiledContract( + p evm.StatefulPrecompiledContract, + caller common.Address, // address arg is unused + input []byte, + suppliedGas uint64, + value *big.Int, +) (ret []byte, remainingGas uint64, err error) { + gasCost := p.RequiredGas(input) + if suppliedGas < gasCost { + return nil, 0, vm.ErrOutOfGas + } + suppliedGas -= gasCost + //output, err := p.RunStateful(e, caller, input, value) + return nil, suppliedGas, err +} + // 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 vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, commit bool) (ret []byte, leftOverGas uint64, err error) { // Fail if we're trying to execute above the call depth limit oEVM := reflect.ValueOf(evm.EVM).Elem() depthValue := oEVM.FieldByName("depth") @@ -173,7 +191,11 @@ func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, g if isPrecompile { if customPrecompiledContracts[addr] != nil { - ret, gas, err = evm.RunStatefulPrecompiledContract(customPrecompiledContracts[addr], caller.Address(), input, gas, value) + if !commit { + ret, gas, err = evm.PreRunStatefulPrecompiledContract(customPrecompiledContracts[addr], caller.Address(), input, gas, value) + } else { + ret, gas, err = evm.RunStatefulPrecompiledContract(customPrecompiledContracts[addr], caller.Address(), input, gas, value) + } } else { ret, gas, err = vm.RunPrecompiledContract(p, input, gas) } diff --git a/x/evm/vm/interface.go b/x/evm/vm/interface.go index 1007344fd5..4bf1342e19 100644 --- a/x/evm/vm/interface.go +++ b/x/evm/vm/interface.go @@ -42,7 +42,7 @@ type EVM interface { Cancel() Cancelled() bool //nolint Interpreter() *vm.EVMInterpreter - Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) + Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, commit bool) (ret []byte, leftOverGas uint64, err error) CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)