-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OOGX tests using BytecodeRunner.runOnlyForGasCost + MSIZE #1783
base: arith-dev
Are you sure you want to change the base?
Conversation
b9307f9
to
490f443
Compare
4fe31f2
to
f449242
Compare
7e06004
to
af937c1
Compare
...hmetization/src/test/java/net/consensys/linea/zktracer/exceptions/OutOfGasExceptionTest.java
Show resolved
Hide resolved
...hmetization/src/test/java/net/consensys/linea/zktracer/exceptions/OutOfGasExceptionTest.java
Outdated
Show resolved
Hide resolved
...hmetization/src/test/java/net/consensys/linea/zktracer/exceptions/OutOfGasExceptionTest.java
Outdated
Show resolved
Hide resolved
...hmetization/src/test/java/net/consensys/linea/zktracer/exceptions/OutOfGasExceptionTest.java
Show resolved
Hide resolved
...hmetization/src/test/java/net/consensys/linea/zktracer/exceptions/OutOfGasExceptionTest.java
Show resolved
Hide resolved
.op(OpCode.MSIZE) | ||
.push(0xFF) | ||
.push(1) // expand memory | ||
.op(OpCode.MSTORE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Obvious remark: both MSTORE
's expand memory, the first to size 0x20
, the second to size 0x40
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it felt better to go from a non-zero value to a non-zero value, but it's strictly the same behavior. Let me simplify it 👍
...ation/src/test/java/net/consensys/linea/zktracer/exceptions/OutOfGasMemExpExceptionTest.java
Outdated
Show resolved
Hide resolved
bytecodeRunner.run(Wei.fromEth(1), gasCost + cornerCase, List.of(), calldata); | ||
if (cornerCase == -1) { | ||
assertEquals( | ||
OUT_OF_GAS_EXCEPTION, | ||
bytecodeRunner.getHub().previousTraceSection().commonValues.tracedException()); | ||
} else { | ||
assertNotEquals( | ||
OUT_OF_GAS_EXCEPTION, | ||
bytecodeRunner.getHub().previousTraceSection().commonValues.tracedException()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This paragraph could be extracted into a method I imagine ? It's duplicated quite a number of times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I created a Utils method 👌
.push(0) // offset | ||
.push(33) // destoffset | ||
.op(OpCode.DUP4) // | ||
.op(OpCode.EXTCODECOPY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would make sense to rename this test to
void outOfGasExceptionWarmExtCodeCopy(int cornerCase) { ... }
(the address in question will be warm after the successful deployment) and to add a second test called e.g. outOfGasExceptionColdExtCodeCopy
where you
- define a
ToyAccount
with addressc0deadd7e55
, provide it with byte code that is e.g. simply"ff".repeat(foreignCodeSize)
where you setfinal int foreignCodeSize = 70;
, say, and add it to the list of accounts in the test - then run the following code in the root
program
.push(foreignCodeSize + 3) // size
.push(11) // offset
.push(33) // destoffset
.push("c0deadd7e55") // address
.op(OpCode.EXTCODECOPY);
This test targets a cold account and will read out of bounds of its code.
...ation/src/test/java/net/consensys/linea/zktracer/exceptions/OutOfGasMemExpExceptionTest.java
Outdated
Show resolved
Hide resolved
.push(32) // size | ||
.push(0) // offset | ||
.push(65) // destoffset, trigger mem expansion | ||
.op(OpCode.RETURNDATACOPY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more of a side note than anything.
The above could be achieved more directly. Currently you
- pre-populate the state with an account at address
c0de
with some code EXTCODECOPY
this code in full- use this code as the init code of a
CREATE
which deploys a new SMC with code I'll callreturnDataProviderCode
STATICCALL
into this account, thus producing some nonempty return data
You could shortcircuit the first steps and instead
- pre-populate the state with an account at address
c0de
withreturnDataProviderCode
STATICCALL
into thec0de
account, thus producing some nonempty return data
The bytecode would be
program
.push(0) // byte size of return data
.push(0) // retOffset
.push(0) // byte size calldata
.push(0) // argsOffset
.op("c0de") // address of 'return data provider' account
.op(OpCode.GAS) // gas
.op(OpCode.STATICCALL)
// 3. Clean the stack
.op(OpCode.POP)
// 4. Return data copy
.push(32) // size
.push(0) // offset
.push(65) // destoffset, trigger mem expansion
.op(OpCode.RETURNDATACOPY);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also suggest to add a variant of the above where we do the following
program
.push(0) // byte size of return data
.push(0) // retOffset
.push(0) // byte size calldata
.push(0) // argsOffset
.op("c0de") // address of 'return data provider' account
.op(OpCode.GAS) // gas
.op(OpCode.STATICCALL)
// 3. Clean the stack
.op(OpCode.POP)
// 4. Doubly exceptional return data copy
.op(OpCode.RETURNDATASIZE)
.push(1)
.op(OpCode.ADD); // size = RDS + 1, which will trigger the `returnDataCopyException`
.push(0) // offset
.push(65) // destoffset, trigger mem expansion
.op(OpCode.RETURNDATACOPY);
We could name this test to doubleExceptionReturnDataCopyTestOogxAndRdcx
. We have so far not written tests where we deliberately trigger several exceptions at once.
...ation/src/test/java/net/consensys/linea/zktracer/exceptions/OutOfGasMemExpExceptionTest.java
Show resolved
Hide resolved
Bytes pgCompile = program.compile(); | ||
BytecodeRunner bytecodeRunner = BytecodeRunner.of(pgCompile); | ||
|
||
long gasCost = bytecodeRunner.runOnlyForGasCost(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure this is the correct gasCost
? I'm asking because a naïve implementation of runOnlyForGasCost
would compute the total gas consumed by the transaction, say. But this would include the PUSH
's and MSTORE
's and RETURN
's of the deployment inside the CREATE
. Are we sure those costs aren't taken into account when running runOnlyForGasCost
?
What we need here is the cost just up to an including the upfrontGasCost
of the CREATE
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I guess this is what the 6420
etc is about ...
bytecodeRunner.getHub().previousTraceSection().commonValues.tracedException()); | ||
assertEquals( | ||
OUT_OF_GAS_EXCEPTION, | ||
bytecodeRunner.getHub().previousTraceSection(2).commonValues.tracedException()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this OUT_OF_GAS_EXCEPTION
happening inside of the deployment frame ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes exactly, can it be checked in a better way ? It's the case where the deployment frame has enough gas to run the code but not enough to cover the depositFee, so it triggers an OOGX
|
||
@ParameterizedTest | ||
@ValueSource(ints = {-1, 0, 1}) | ||
void outOfGasExceptionJumpi(int cornerCase) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, too, we have the opportunity to test simultaneous exceptions, in this case:
jumpException
outOfGasException
And it would be trivial to implement, just switch the second push to
final Bytes bytecode =
BytecodeCompiler.newProgram()
.push(1) // pc = 0, 1
.push(6) // pc = 2, 3
// ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would make sense to create a new class for these MultiExceptionTests
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which would include the RETURNDATACOPY
double exception test mentioned earlier.
OUT_OF_GAS_EXCEPTION, | ||
bytecodeRunner.getHub().previousTraceSection().commonValues.tracedException()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In terms of MultiExceptionsTest
one could have a simple test where one triggers simultaneously
staticException
outOfGasException
or
staticException
stackUnderflowException
One needs two smart contracts with byte code
BytecodeCompiler simpleLog0 = BytecodeCompiler.newProgram();
simpleLog0.push(0).push(0).op(LOG0);
BytecodeCompiler stackUnderflowLog0 = BytecodeCompiler.newProgram();
stackUnderflowLog0.push(0).op(LOG0);
Which are called upon through a STATICCALL
with gas = 3 + 3 + 375 + cornerCase
/ gas = 3 + 375 + cornerCase
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left several comments
Closes #1685
BytecodeRunner.runOnlyForGasCost
Method to calculate cost dynamically - based on LondonGasCalculator (Besu)opCodeToOpCodeDataMap.values()
without opcodes with mem expansion costLocal benchmark done on 366 tests with
BytecodeRunner.run
twice 2min50sTest coverage improvement
+7 lines covered
+4 conditions covered
Results
+0.3% condition coverage on Unit tests
+0.1% overall coverage score (with blockchain ref tests)