diff --git a/fhevm/contracts_test.go b/fhevm/contracts_test.go index 0ea0dbd..97a903c 100644 --- a/fhevm/contracts_test.go +++ b/fhevm/contracts_test.go @@ -3153,16 +3153,6 @@ func TestFheRandEthCall(t *testing.T) { } } -func interpreterRunWithStopContract(environment *MockEVMEnvironment, interpreter *vm.EVMInterpreter, contract *vm.Contract, input []byte, readOnly bool) (ret []byte, err error) { - ret, _ = interpreter.Run(contract, input, readOnly) - // the following functions are meant to be ran from within interpreter.run so we increment depth to emulate that - environment.depth++ - RemoveVerifiedCipherextsAtCurrentDepth(environment) - err = EvalRemOptReqWhenStopToken(environment) - environment.depth-- - return ret, err -} - func newInterpreterFromEnvironment(environment *MockEVMEnvironment) *vm.EVMInterpreter { cfg := vm.Config{} evm := &vm.EVM{Config: cfg} @@ -3206,7 +3196,7 @@ func TestLibOneTrueOptimisticRequire(t *testing.T) { interpreter := newInterpreterFromEnvironment(environment) // Call the interpreter with a single STOP opcode and expect that the optimistic require doesn't revert. - out, err = interpreterRunWithStopContract(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) + out, err = InterpreterRun(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) if err != nil { t.Fatalf(err.Error()) } else if out != nil { @@ -3230,7 +3220,7 @@ func TestOneFalseOptimisticRequire(t *testing.T) { } interpreter := newInterpreterFromEnvironment(environment) // Call the interpreter with a single STOP opcode and expect that the optimistic require reverts. - out, err = interpreterRunWithStopContract(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) + out, err = InterpreterRun(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) if err == nil || err != ErrExecutionReverted { t.Fatalf("require expected reversal on value 0") } else if out != nil { @@ -3261,7 +3251,7 @@ func TestTwoTrueOptimisticRequires(t *testing.T) { } interpreter := newInterpreterFromEnvironment(environment) // Call the interpreter with a single STOP opcode and expect that the optimistic require doesn't revert. - out, err = interpreterRunWithStopContract(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) + out, err = InterpreterRun(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) if err != nil { t.Fatalf(err.Error()) } else if out != nil { @@ -3292,7 +3282,7 @@ func TestOptimisticRequireTwiceOnSameCiphertext(t *testing.T) { } interpreter := newInterpreterFromEnvironment(environment) // Call the interpreter with a single STOP opcode and expect that the optimistic require doesn't revert. - out, err = interpreterRunWithStopContract(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) + out, err = InterpreterRun(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) if err != nil { t.Fatalf(err.Error()) } else if out != nil { @@ -3322,7 +3312,7 @@ func TestOneFalseAndOneTrueOptimisticRequire(t *testing.T) { } interpreter := newInterpreterFromEnvironment(environment) // Call the interpreter with a single STOP opcode and expect that the optimistic require reverts. - out, err = interpreterRunWithStopContract(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) + out, err = InterpreterRun(environment, interpreter, newStopOpcodeContract(), make([]byte, 0), readOnly) if err == nil || err != ErrExecutionReverted { t.Fatalf("require expected reversal on value 0") } else if out != nil { diff --git a/fhevm/instructions.go b/fhevm/instructions.go index f2a08a1..07135d1 100644 --- a/fhevm/instructions.go +++ b/fhevm/instructions.go @@ -335,15 +335,15 @@ func delegateCiphertextHandlesToCaller(env EVMEnvironment, ret []byte) { } } -func RemoveVerifiedCipherextsAtCurrentDepth(env EVMEnvironment) { +func RemoveVerifiedCipherextsAtCurrentDepth(env EVMEnvironment, depth int) { for _, verifiedCiphertext := range env.FhevmData().verifiedCiphertexts { if env.IsCommitting() { env.GetLogger().Info("Run removing ciphertext from depth", "handle", verifiedCiphertext.ciphertext.getHash().Hex(), - "depth", env.GetDepth()) + "depth", depth) } // Delete the current EVM depth from the set of verified depths. - verifiedCiphertext.verifiedDepths.del(env.GetDepth()) + verifiedCiphertext.verifiedDepths.del(depth) } } diff --git a/fhevm/interpreter.go b/fhevm/interpreter.go index 8b813e6..0f07cf3 100644 --- a/fhevm/interpreter.go +++ b/fhevm/interpreter.go @@ -2,6 +2,7 @@ package fhevm import ( "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" ) type ScopeContext interface { @@ -67,17 +68,32 @@ var PrivilegedMempory *PrivilegedMemory = &PrivilegedMemory{ // // This function is meant to be integrated as part of vm.EVMInterpreter.Run in the case // there was an errStopToken -func EvalRemOptReqWhenStopToken(env EVMEnvironment) (err error) { - err = nil +func EvalRemOptReqWhenStopToken(env EVMEnvironment, depth int) (err error) { // If we are finishing execution (about to go to from depth 1 to depth 0), evaluate // any remaining optimistic requires. - if env.GetDepth() == 1 { + if depth == 1 { result, evalErr := evaluateRemainingOptimisticRequires(env) if evalErr != nil { - err = evalErr + return evalErr } else if !result { - err = ErrExecutionReverted + return ErrExecutionReverted } } - return err + return nil +} + +// Function meant to be run instead of vm.EVMInterpreter.Run inside an fhEVM +// +// It makes sure to remove ciphertexts used at current depth during interpreter execution, but also evaluate remaining optimistic requires if necessary +func InterpreterRun(environment EVMEnvironment, interpreter *vm.EVMInterpreter, contract *vm.Contract, input []byte, readOnly bool) (ret []byte, err error) { + ret, err = interpreter.Run(contract, input, readOnly) + // the following functions are meant to be ran from within interpreter.Run so we increment depth to emulate that + depth := environment.GetDepth() + 1 + RemoveVerifiedCipherextsAtCurrentDepth(environment, depth) + // if contract is not empty and err is nil, then an errStopToken was cleared inside interpreter.Run + if len(contract.Code) != 0 && err == nil { + err = EvalRemOptReqWhenStopToken(environment, depth) + return ret, err + } + return ret, err }