From e7298857417877bb0a603cd261fd4e0bb20b9b3c Mon Sep 17 00:00:00 2001 From: Mason Liang Date: Mon, 24 Jan 2022 16:16:19 -0500 Subject: [PATCH 1/4] Update file name reference --- specs/opcode/41COINBASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/opcode/41COINBASE.md b/specs/opcode/41COINBASE.md index 7ec0cade6..aa229c1ea 100644 --- a/specs/opcode/41COINBASE.md +++ b/specs/opcode/41COINBASE.md @@ -36,4 +36,4 @@ then push the `address` to the stack. ## Code -Please refer to `src/zkevm_specs/evm/execution/coinbase.py`. +Please refer to `src/zkevm_specs/evm/execution/block_coinbase.py`. From 8ae9dcb0072ee90cb28f25c637749f96f1860b3a Mon Sep 17 00:00:00 2001 From: Mason Liang Date: Mon, 24 Jan 2022 16:17:07 -0500 Subject: [PATCH 2/4] Add TIMESTAMP spec --- specs/opcode/42TIMESTAMP.md | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 specs/opcode/42TIMESTAMP.md diff --git a/specs/opcode/42TIMESTAMP.md b/specs/opcode/42TIMESTAMP.md new file mode 100644 index 000000000..d18550e30 --- /dev/null +++ b/specs/opcode/42TIMESTAMP.md @@ -0,0 +1,39 @@ +# Timestamp op code + +## Procedure + +The `TIMESTAMP` opcode pushes the timestamp of the current block onto the stack. + +## EVM behavior + +The `TIMESTAMP` opcode loads a `timestamp` (8 bytes of data) from the block context and then +pushes it onto the stack. + +## Circuit behavior + +1. construct block context table +2. do busmapping lookup for stack write operation +3. other implicit check: bytes length + +## Constraints + +1. opId = 0x42 +2. State transition: + - gc + 1 (1 stack write) + - stack_pointer - 1 + - pc + 1 + - gas + 2 +3. Lookups: 2 + - `timestamp` is on the top of stack + - `timestamp` is in the block context table +4. Others: + - `timestamp` fits into 8 bytes + +## Exceptions + +1. stack overflow: stack is full, stack pointer = 0 +2. out of gas: remaining gas is not enough + +## Code + +Please refer to `src/zkevm_specs/evm/execution/block_timestamp.py`. From b84781c0a0c76f481d7fedfcfdad39852c93d231 Mon Sep 17 00:00:00 2001 From: Mason Liang Date: Mon, 24 Jan 2022 16:17:33 -0500 Subject: [PATCH 3/4] Add TIMESTAMP implementation and test --- src/zkevm_specs/evm/execution/__init__.py | 2 + .../evm/execution/block_timestamp.py | 22 +++++++ tests/evm/test_timestamp.py | 64 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/zkevm_specs/evm/execution/block_timestamp.py create mode 100644 tests/evm/test_timestamp.py diff --git a/src/zkevm_specs/evm/execution/__init__.py b/src/zkevm_specs/evm/execution/__init__.py index 9a8e3deab..e290a43fe 100644 --- a/src/zkevm_specs/evm/execution/__init__.py +++ b/src/zkevm_specs/evm/execution/__init__.py @@ -12,6 +12,7 @@ from .jumpi import * from .push import * from .block_coinbase import * +from .block_timestamp import * from .caller import * from .slt_sgt import * from .callvalue import * @@ -27,6 +28,7 @@ ExecutionState.CALLVALUE: callvalue, ExecutionState.CALLDATASIZE: calldatasize, ExecutionState.COINBASE: coinbase, + ExecutionState.TIMESTAMP: timestamp, ExecutionState.JUMP: jump, ExecutionState.JUMPI: jumpi, ExecutionState.PUSH: push, diff --git a/src/zkevm_specs/evm/execution/block_timestamp.py b/src/zkevm_specs/evm/execution/block_timestamp.py new file mode 100644 index 000000000..16c95bfe6 --- /dev/null +++ b/src/zkevm_specs/evm/execution/block_timestamp.py @@ -0,0 +1,22 @@ +from ..instruction import Instruction, Transition +from ..table import BlockContextFieldTag +from ..opcode import Opcode + + +def timestamp(instruction: Instruction): + opcode = instruction.opcode_lookup(True) + instruction.constrain_equal(opcode, Opcode.TIMESTAMP) + timestamp = instruction.stack_push() + # in real circuit also check timestamp raw data is 64 bit length (8 bytes) + # check block table for timestamp + instruction.constrain_equal( + timestamp, + instruction.block_context_lookup(BlockContextFieldTag.Timestamp), + ) + + instruction.step_state_transition_in_same_context( + opcode, + rw_counter=Transition.delta(1), + program_counter=Transition.delta(1), + stack_pointer=Transition.delta(-1), + ) diff --git a/tests/evm/test_timestamp.py b/tests/evm/test_timestamp.py new file mode 100644 index 000000000..ccfe66837 --- /dev/null +++ b/tests/evm/test_timestamp.py @@ -0,0 +1,64 @@ +import pytest + +from zkevm_specs.evm import ( + ExecutionState, + StepState, + verify_steps, + Tables, + RWTableTag, + RW, + Block, + Bytecode, +) +from zkevm_specs.util import rand_range, rand_fp, RLC, U64 + +TESTING_DATA = (0, 1, 2**64 - 1, rand_range(2**64)) + +@pytest.mark.parametrize("timestamp", TESTING_DATA) +def test_timestamp(timestamp: U64): + randomness = rand_fp() + + block = Block(timestamp=timestamp) + + bytecode = Bytecode().timestamp() + bytecode_hash = RLC(bytecode.hash(), randomness) + + tables = Tables( + block_table=set(block.table_assignments(randomness)), + tx_table=set(), + bytecode_table=set(bytecode.table_assignments(randomness)), + rw_table=set( + [ + (9, RW.Write, RWTableTag.Stack, 1, 1023, RLC(timestamp, randomness, 8), 0, 0), + ] + ), + ) + + verify_steps( + randomness=randomness, + tables=tables, + steps=[ + StepState( + execution_state=ExecutionState.TIMESTAMP, + rw_counter=9, + call_id=1, + is_root=True, + is_create=False, + code_source=bytecode_hash, + program_counter=0, + stack_pointer=1024, + gas_left=2, + ), + StepState( + execution_state=ExecutionState.STOP, + rw_counter=10, + call_id=1, + is_root=True, + is_create=False, + code_source=bytecode_hash, + program_counter=1, + stack_pointer=1023, + gas_left=0, + ), + ], + ) From 8642d6c98b1086acb4c9499bcc5b6b17ef16cbf3 Mon Sep 17 00:00:00 2001 From: Mason Liang Date: Mon, 24 Jan 2022 16:23:29 -0500 Subject: [PATCH 4/4] black --- tests/evm/test_timestamp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/evm/test_timestamp.py b/tests/evm/test_timestamp.py index ccfe66837..e44979050 100644 --- a/tests/evm/test_timestamp.py +++ b/tests/evm/test_timestamp.py @@ -12,7 +12,8 @@ ) from zkevm_specs.util import rand_range, rand_fp, RLC, U64 -TESTING_DATA = (0, 1, 2**64 - 1, rand_range(2**64)) +TESTING_DATA = (0, 1, 2 ** 64 - 1, rand_range(2 ** 64)) + @pytest.mark.parametrize("timestamp", TESTING_DATA) def test_timestamp(timestamp: U64):