Consensys / linea-tracer

Part of the Linea stack responsible for extracting data from the execution of an EVM client in order to construct large matrices called execution traces.
https://linea.build
Other
35 stars 25 forks source link

`CREATE/deployment transaction` different behaviours wrt triggering `INVALID_CODE_PREFIX` and `MAX_CODE_SIZE` exceptions #1460

Open lorenzogentile404 opened 3 weeks ago

lorenzogentile404 commented 3 weeks ago

In this testing class we deliberately try to trigger the INVALID_CODE_PREFIX and MAX_CODE_SIZE. The first two tests of the class try to achieve it by executing a deployment transaction with a payload that returns a portion of memory starting with EIP_3541_MARKER or greater than MAX_CODE_SIZE respectively. The last two, achieves the same result by using CREATE instead of a deployment transaction. What we observe is that, while the last two tests correctly trigger the expected exceptions, the first two encounter a Java exceptions that seems to be related to Besu. Below the exceptions we encounter:

First test:

11:37:16.993 [Test worker] DEBUG - Transaction 0xf9f77d7caa32abd068a5b173d70723a9590d1ddaae859689a840875676eb54bd processing halted: INVALID_CODE

Transaction: 0xf9f77d7caa32abd068a5b173d70723a9590d1ddaae859689a840875676eb54bd not successful. TransactionProcessingResult{status=FAILED, estimateGasUsedByTransaction=16777215, gasRemaining=0, logs=[], output=0x, validationResult=ValidationResult{invalidReason=Optional[EXECUTION_HALTED], errorMessage=Optional[INVALID_CODE]}, revertReason=Optional.empty}
Expected :true
Actual   :false
<Click to see difference>

org.opentest4j.AssertionFailedError: Transaction: 0xf9f77d7caa32abd068a5b173d70723a9590d1ddaae859689a840875676eb54bd not successful. TransactionProcessingResult{status=FAILED, estimateGasUsedByTransaction=16777215, gasRemaining=0, logs=[], output=0x, validationResult=ValidationResult{invalidReason=Optional[EXECUTION_HALTED], errorMessage=Optional[INVALID_CODE]}, revertReason=Optional.empty} ==> expected: <true> but was: <false>
    at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
    at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
    at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
    at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:42)
    at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:191)
    at net.consensys.linea.testing.TransactionProcessingResultValidator.lambda$static$1(TransactionProcessingResultValidator.java:30)
    at net.consensys.linea.testing.GeneralStateReferenceTestTools.executeTest(GeneralStateReferenceTestTools.java:127)
    at net.consensys.linea.testing.ToyExecutionEnvironmentV2.run(ToyExecutionEnvironmentV2.java:69)
    at net.consensys.linea.zktracer.exceptions.InvalidCodePrefixAndMaxCodeSizeExceptionTest.invalidCodePrefixExceptionForDeploymentTransactionTest(InvalidCodePrefixAndMaxCodeSizeExceptionTest.java:81)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:766)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$8(TestMethodTestDescriptor.java:217)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)

Second test:

11:37:16.936 [Test worker] DEBUG - Transaction 0xce760004f5dfbd94178e8c49d9b010e6c1cecfe896fb98e71431854544c62c9b processing halted: CODE_TOO_LARGE

Transaction: 0xce760004f5dfbd94178e8c49d9b010e6c1cecfe896fb98e71431854544c62c9b not successful. TransactionProcessingResult{status=FAILED, estimateGasUsedByTransaction=16777215, gasRemaining=0, logs=[], output=0x, validationResult=ValidationResult{invalidReason=Optional[EXECUTION_HALTED], errorMessage=Optional[CODE_TOO_LARGE]}, revertReason=Optional.empty}
Expected :true
Actual   :false
<Click to see difference>

org.opentest4j.AssertionFailedError: Transaction: 0xce760004f5dfbd94178e8c49d9b010e6c1cecfe896fb98e71431854544c62c9b not successful. TransactionProcessingResult{status=FAILED, estimateGasUsedByTransaction=16777215, gasRemaining=0, logs=[], output=0x, validationResult=ValidationResult{invalidReason=Optional[EXECUTION_HALTED], errorMessage=Optional[CODE_TOO_LARGE]}, revertReason=Optional.empty} ==> expected: <true> but was: <false>
    at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
    at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
    at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
    at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:42)
    at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:191)
    at net.consensys.linea.testing.TransactionProcessingResultValidator.lambda$static$1(TransactionProcessingResultValidator.java:30)
    at net.consensys.linea.testing.GeneralStateReferenceTestTools.executeTest(GeneralStateReferenceTestTools.java:127)
    at net.consensys.linea.testing.ToyExecutionEnvironmentV2.run(ToyExecutionEnvironmentV2.java:69)
    at net.consensys.linea.zktracer.exceptions.InvalidCodePrefixAndMaxCodeSizeExceptionTest.maxCodeSizeExceptionForDeploymentTransactionTest(InvalidCodePrefixAndMaxCodeSizeExceptionTest.java:118)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:766)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$8(TestMethodTestDescriptor.java:217)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)

@Gabriel-Trintinalia suggested this:

I believe it happens because of the ContractCreationValidation rules. In here -> ExecutionEnvironment class, in the getProtocolSpec try adding

.contractCreationProcessorBuilder(
    evm ->
        new ContractCreationProcessor(
            evm,
            true,
            List.of(),
            1,
            Set.of(Address.fromHexString("0x0000000000000000000000000000000000000003"))))
Gabriel-Trintinalia commented 3 weeks ago

@lorenzogentile404, is it working as expected with the code snipped above? Can we close this issue?

lorenzogentile404 commented 3 weeks ago

As discussed in our call, while the tests are passing with this patch (and also if we provide an empty set of addresses), the patch leads to a bug in the tracer where Besu says transactions are successful while we expect them to fail in the two tests using a deployment transaction @Gabriel-Trintinalia @OlivierBBB

OlivierBBB commented 3 weeks ago

This patch basically disables some exception from the EVM-London (invalidCodePrefixException and maxCodeSizeException, both related to RETURN in deployment contexts) and cannot be integrated.