Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions specs/tables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Tables

For the zkevm we use the following dynamic and fixed tables for lookups to the EVM circuit. The validity of the dynamic tables contents is proved by their own associated circuit.

Code spec at [table.py](../src/zkevm_specs/evm/table.py)

## `tx_table`

Proved by the tx circuit.

| 0 TxID | 1 Tag | 2 | 3 value |
| --- | --- | --- | --- |
| | *TxContextFieldTag* | | |
| $TxID | Nonce | 0 | $value |
| $TxID | Gas | 0 | $value |
| $TxID | GasPrice | 0 | $value |
| $TxID | GasTipCap | 0 | $value |
| $TxID | GasFeeCap | 0 | $value |
| $TxID | CallerAddress | 0 | $value |
| $TxID | CalleeAddress | 0 | $value |
| $TxID | IsCreate | 0 | $value |
| $TxID | Value | 0 | $value |
| $TxID | CallDataLength | 0 | $value |
| $TxID | CallData | $ByteIndex | $value |

## `rw_table`

Proved by the state circuit.

> - **CallContext constant**: read-only data in a call, usually checked with the
> caller before the beginning of a call.
> - **CallContext state**: used by caller to save its own CallState when it's going
> to dive into another call, and will be read out to restore caller's
> CallState in the end by callee.
> - **CallContext last callee**: read-only data inside a call like previous section
> for opcode `RETURNDATASIZE` and `RETURNDATACOPY`, except they will be
> updated when end of callee execution.

| 0 rwc | 1 isWrite | 2 Tag | 3 | 4 | 5 | 6 | 7 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| | | *RwTableTag* | | | | | |
| $counter | true | TxAccessListAccount | $TxID | $address | $value | $value_prev | 0 |
| $counter | true | TxAccessListAccountStorage | $TxID | $address | $key | $value | $value_prev |
| $counter | $isWrite | TxRefund | $TxID | $value | $value_prev | 0 | 0 |
| | | | | | | | |
| | | | | *AccountFieldTag* | | | |
| $counter | $isWrite | Account | $address | Nonce | $value | $value_prev | 0 |
| $counter | $isWrite | Account | $address | Balance | $value | $value_prev | 0 |
| $counter | $isWrite | Account | $address | CodeHash | $value | $value_prev | 0 |
| $counter | true | AccountDestructed | $address | $value | $value_prev | 0 | 0 |
| | | | | | | | |
| | | *CallContext constant* | | *CallContextFieldTag* (ro) | | | |
| $counter | false | CallContext | $callID | RwCounterEndOfReversion | $value | 0 | 0 |
| $counter | false | CallContext | $callID | CallerId | $value | 0 | 0 |
| $counter | false | CallContext | $callID | TxId | $value | 0 | 0 |
| $counter | false | CallContext | $callID | Depth | $value | 0 | 0 |
| $counter | false | CallContext | $callID | CallerAddress | $value | 0 | 0 |
| $counter | false | CallContext | $callID | CalleeAddress | $value | 0 | 0 |
| $counter | false | CallContext | $callID | CallDataOffset | $value | 0 | 0 |
| $counter | false | CallContext | $callID | CallDataLength | $value | 0 | 0 |
| $counter | false | CallContext | $callID | ReturnDataOffset | $value | 0 | 0 |
| $counter | false | CallContext | $callID | ReturnDataLength | $value | 0 | 0 |
| $counter | false | CallContext | $callID | Value | $value | 0 | 0 |
| $counter | false | CallContext | $callID | Result | $value | 0 | 0 |
| $counter | false | CallContext | $callID | IsPersistent | $value | 0 | 0 |
| $counter | false | CallContext | $callID | IsStatic | $value | 0 | 0 |
| | | | | | | | |
| | | *CallContext last callee* | | *CallContextFieldTag* (rw) | | | |
| $counter | false | CallContext | $callID | LastCalleeId | $value | 0 | 0 |
| $counter | false | CallContext | $callID | LastCalleeReturnDataOffset | $value | 0 | 0 |
| $counter | false | CallContext | $callID | LastCalleeReturnDataLength | $value | 0 | 0 |
| | | | | | | | |
| | | *CallContext state* | | *CallContextFieldTag* (rw) | | | |
| $counter | $isWrite | CallContext | $callID | IsRoot | $value | 0 | 0 |
| $counter | $isWrite | CallContext | $callID | IsCreate | $value | 0 | 0 |
| $counter | $isWrite | CallContext | $callID | CodeSource | $value | 0 | 0 |
| $counter | $isWrite | CallContext | $callID | ProgramCounter | $value | 0 | 0 |
| $counter | $isWrite | CallContext | $callID | StackPointer | $value | 0 | 0 |
| $counter | $isWrite | CallContext | $callID | GasLeft | $value | 0 | 0 |
| $counter | $isWrite | CallContext | $callID | MemorySize | $value | 0 | 0 |
| $counter | $isWrite | CallContext | $callID | StateWriteCounter | $value | 0 | 0 |
| | | | | | | | |
| $counter | $isWrite | Stack | $callID | $stackPointer | $value | 0 | 0 |
| $counter | $isWrite | Memory | $callID | $address | $value | 0 | 0 |
| $counter | $isWrite | AccountStorage | $address | $key | $value | $valuePrev | 0 |

## `bytecode_table`

Proved by the bytecode circuit.

> - **isCode**: A boolean value to specify if the value is executable opcode or
> the data portion of PUSH\* operations.

| 0 codeHash | 1 byteIndex | 2 value | 3 isCode |
| --- | --- | --- | --- |
| $codeHash | $byteIndex | $value | $isCode |

## `block_table`

Proved by the block circuit.

| 0 Tag | 1 | 2 value |
| --- | --- | --- |
| *BlockContextFieldTag* | | |
| Coinbase | 0 | $value |
| GasLimit | 0 | $value |
| BlockNumber | 0 | $value |
| Time | 0 | $value |
| Difficulty | 0 | $value |
| BaseFee | 0 | $value |
| BlockHash | 0..256 | $value |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is currently implemented as the actual block number. For example, if current block has number 300, then the number here will be 44..300, like:

https://github.com/appliedzkp/zkevm-specs/blob/ffcc9295442bccd7bf23646ee9eb2565aef9ff82/src/zkevm_specs/evm/typing.py#L60-L63

But after more thought on this, I think we should keep it simpler for verifier to have as 0..256, since the constraints of BLOCKHASH would be almost same (differs on whether to subtract block.number or not).

Will try to update it in further PRs.


## `fixed`

> - **execution_state.responsible_opcode()**: map execution_state (opcode's
> successful cases, where multiple similar opcodes may be merged into a
> single execution state, like `LT`, `GT`, `EQ` in `CMP` state) to opcode
> that can generate that execution state.
> - **invalid_opcodes()**: set of invalid opcodes
> - **state_write_opcodes()**: set of opcodes that write the state.
> - **stack_underflow_pairs**: set of opcodes and stack pointer value that
> causes underflow during execution.
> - **stack_overflow_pairs**: set of opcodes and stack pointer value that
> causes overflow during execution.

| 0 Tag | 1 | 2 | 3 |
| --- | --- | --- | --- |
| *FixedTableTag* | | | |
| Range16 | 0..16 | 0 | 0 |
| Range32 | 0..32 | 0 | 0 |
| Range64 | 0..64 | 0 | 0 |
| Range256 | 0..256 | 0 | 0 |
| Range512 | 0..512 | 0 | 0 |
| Range1024 | 0..1024 | 0 | 0 |
| SignByte | value=0..256 | if (value as i8 \< 0) 0xff else 0 | 0 |
| BitwiseAnd | lhs=0..256 | rhs=0..256 | $lhs AND $rhs |
| BitwiseOr | lhs=0..256 | rhs=0..256 | $lhs OR $rhs |
| BitwiseXor | lhs=0..256 | rhs=0..256 | $lhs XOR $rhs |
| ResponsibleOpcode | $execution_state | execution_state.responsible_opcode() | 0 |
| InvalidOpcode | invalid_opcodes() | 0 | 0 |
| StateWriteOpcode | state_write_opcodes() | 0 | 0 |
| StackOverflow | $overflow_opcode | stack_overflow_pairs\[overflow_opcode\] | 0 |
| StackUnderflow | $underflow_opcode | stack_underflow_pairs\[underflow_opcode\] | 0 |