-
Notifications
You must be signed in to change notification settings - Fork 77
[WIP] add ErrorDepth specs
#52
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # ErrorDepth state | ||
|
|
||
| ## Procedure | ||
| For CALL-family codes this type of error occurs when causing a callstack overflow. | ||
|
|
||
| ### EVM behavior | ||
| 1. Fail the call attempt resulting in pushing `0` into stack | ||
| 2. Continue the execution of current context | ||
|
|
||
| ### Constraints | ||
| 1. Current opcode must be CALL-family codes. | ||
| 2. `depth == 1025`. | ||
| 3. The next step with `0` on stack top. | ||
|
|
||
| ### Lookups | ||
| - 1 Call Context lookup `CallContextFieldTag.Depth` | ||
| - 1 Stack push lookup | ||
|
|
||
| ## Code | ||
|
|
||
| Please refer to `src/zkevm_specs/evm/execution/error_depth.py`. | ||
|
|
||
| ### Solidity Code to trigger ErrorDepth | ||
| ```solidity | ||
| PUSH32 0x7f602060006000376000600060206000600060003561ffff5a03f10000000000 | ||
| PUSH1 0x0 | ||
| MSTORE | ||
| PUSH32 0x0060005260206000F30000000000000000000000000000000000000000000000 | ||
| PUSH1 0x20 | ||
| MSTORE | ||
|
|
||
| PUSH1 0x40 | ||
| PUSH1 0x0 | ||
| PUSH1 0x0 | ||
| CREATE | ||
|
|
||
| DUP1 | ||
| PUSH1 0x40 | ||
| MSTORE | ||
|
|
||
| PUSH1 0x0 // retSize | ||
| PUSH1 0x0 // retOffset | ||
| PUSH1 0x20 // argSize | ||
| PUSH1 0x40 // argOffset | ||
| PUSH1 0x0 // Value | ||
| DUP6 | ||
| PUSH2 0xFF | ||
| GAS | ||
| SUB | ||
| CALL | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| from ...util import FQ | ||
| from ..instruction import Instruction, Transition | ||
| from ..opcode import Opcode | ||
| from ..table import CallContextFieldTag | ||
|
|
||
|
|
||
| def error_depth(instruction: Instruction): | ||
| opcode = instruction.opcode_lookup(True) | ||
| # current executing op code must be CALL-family | ||
| instruction.constrain_in( | ||
| opcode, | ||
| [FQ(Opcode.CALL), FQ(Opcode.CALLCODE), FQ(Opcode.DELEGATECALL), FQ(Opcode.STATICCALL)] | ||
| ) | ||
|
|
||
| is_call, is_callcode, is_delegatecall, is_staticcall = instruction.multiple_select( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't need to check it is call or call code etc.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but CALL and CALLCODE will consume 7 stack elements and DELEGATECALL and STATICCALL will consume 6 elements |
||
| opcode, (Opcode.CALL, Opcode.CALLCODE, Opcode.DELEGATECALL, Opcode.STATICCALL) | ||
| ) | ||
|
|
||
| stack_delta = 0 | ||
| if is_call or is_callcode: | ||
| stack_delta -= 7 | ||
| elif is_delegatecall or is_delegatecall: | ||
| stack_delta -= 6 | ||
|
|
||
| # next step must have zero on stack top | ||
| is_zero = instruction.stack_push() | ||
| stack_delta += 1 | ||
| instruction.constrain_equal(is_zero, FQ(0)) | ||
|
|
||
| # check the call depth | ||
| depth = instruction.call_context_lookup(CallContextFieldTag.Depth) | ||
| instruction.constrain_equal(depth, FQ(1025)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be 1024 because current look up is for caller's depth |
||
|
|
||
| instruction.step_state_transition_in_same_context( | ||
| opcode, | ||
| rw_counter=Transition.delta(2), | ||
| program_counter=Transition.delta(1), | ||
| stack_pointer=Transition.delta(stack_delta) | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| import pytest | ||
| from collections import namedtuple | ||
| from itertools import chain | ||
|
|
||
| from zkevm_specs.evm import ( | ||
| Block, | ||
| Bytecode, | ||
| CallContextFieldTag, | ||
| ExecutionState, | ||
| Opcode, | ||
| RWDictionary, | ||
| StepState, | ||
| Tables, | ||
| Transaction, | ||
| verify_steps, | ||
| ) | ||
| from zkevm_specs.util import rand_fq, RLC | ||
|
|
||
| BYTECODE = Bytecode().call() | ||
| TESTING_DATA_IS_ROOT = ((Transaction(), BYTECODE),) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("tx, bytecode", TESTING_DATA_IS_ROOT) | ||
| def test_depth(tx: Transaction, bytecode: Bytecode): | ||
| randomness = rand_fq() | ||
|
|
||
| block = Block() | ||
|
|
||
| bytecode_hash = RLC(bytecode.hash(), randomness) | ||
|
|
||
| tables = Tables( | ||
| block_table=set(block.table_assignments(randomness)), | ||
| tx_table=set( | ||
| chain( | ||
| tx.table_assignments(randomness), | ||
| Transaction(id=tx.id + 1).table_assignments(randomness), | ||
| ) | ||
| ), | ||
| bytecode_table=set(bytecode.table_assignments(randomness)), | ||
| rw_table=set( | ||
| RWDictionary(24) | ||
| .call_context_read(1, CallContextFieldTag.Depth, 1025) | ||
| .rws | ||
| ), | ||
| ) | ||
|
|
||
| verify_steps( | ||
| randomness=randomness, | ||
| tables=tables, | ||
| steps=[ | ||
| StepState( | ||
| execution_state=ExecutionState.ErrorDepth, | ||
| rw_counter=24, | ||
| call_id=1, | ||
| is_root=True, | ||
| is_create=False, | ||
| code_hash=bytecode_hash, | ||
| program_counter=0, | ||
| stack_pointer=1023, | ||
| gas_left=2, | ||
| reversible_write_counter=2, | ||
| ) | ||
| ], | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.