From 72308062b487af5f7403eb0230070110228379ac Mon Sep 17 00:00:00 2001 From: Dream Wu Date: Tue, 28 Dec 2021 14:12:31 +0800 Subject: [PATCH 01/10] update as dependency pr changed --- specs/opcode/41COINBASE.md | 42 +++++++++++ src/zkevm_specs/evm/execution/__init__.py | 1 + .../evm/execution/block_coinbase.py | 20 ++++++ src/zkevm_specs/evm/main.py | 3 + tests/evm/test_coinbase.py | 70 +++++++++++++++++++ 5 files changed, 136 insertions(+) create mode 100644 specs/opcode/41COINBASE.md create mode 100644 src/zkevm_specs/evm/execution/block_coinbase.py create mode 100644 tests/evm/test_coinbase.py diff --git a/specs/opcode/41COINBASE.md b/specs/opcode/41COINBASE.md new file mode 100644 index 000000000..6c7a37a18 --- /dev/null +++ b/specs/opcode/41COINBASE.md @@ -0,0 +1,42 @@ +# Coinbase op code + +## Procedure + +The `COINBASE` opcode get the coinbase address from current block and push to the stack + +## EVM behavior + +The `COINBASE` opcode loads an `address` (20 bytes of data) from block context. +then push the `address` to the stack. + +## Circuit behavior + +1. construct block context table +2. do bussmapping lookup for stack write operation +3. other implicit check: bytes length + +## Constraints + +1. opId = 0x41 +2. state transition:\ + gc + 1 ( 1 stack write)\ + stack_pointer - 1 + pc + 1\ + gas + 2 +3. lookups: 2 + `address` is on the top of stack + `address` is in block context table + +5. others: + `address` is 20 bytes length + +## Exceptions + +1. gas out:\ + remaining gas is not enough +2. stack overflow:\ + stack is full, stack pointer = 0 + +## Code + +Refer to src/zkevm_specs/evm/execution/coinbase.py diff --git a/src/zkevm_specs/evm/execution/__init__.py b/src/zkevm_specs/evm/execution/__init__.py index 92cfd8e2f..977878b7c 100644 --- a/src/zkevm_specs/evm/execution/__init__.py +++ b/src/zkevm_specs/evm/execution/__init__.py @@ -5,5 +5,6 @@ from .push import * from .jump import * from .jumpi import * +from .block_coinbase import * # Error cases diff --git a/src/zkevm_specs/evm/execution/block_coinbase.py b/src/zkevm_specs/evm/execution/block_coinbase.py new file mode 100644 index 000000000..bba01168e --- /dev/null +++ b/src/zkevm_specs/evm/execution/block_coinbase.py @@ -0,0 +1,20 @@ +from ..instruction import Instruction, Transition +from ..table import BlockContextFieldTag +from ..opcode import Opcode + + +def coinbase(instruction: Instruction): + opcode = instruction.opcode_lookup(True) + instruction.constrain_equal(opcode, Opcode.COINBASE) + address = instruction.stack_push() + # in real circuit also check address raw data is 160 bit length (20 bytes) + # check block table for coinbase address + instruction.constrain_equal(address, + instruction.block_lookup(BlockContextFieldTag.Coinbase)) + + instruction.constrain_same_context_state_transition( + opcode, + rw_counter=Transition.delta(1), + program_counter=Transition.delta(1), + stack_pointer=Transition.delta(-1), + ) diff --git a/src/zkevm_specs/evm/main.py b/src/zkevm_specs/evm/main.py index 4bffd8217..381771de8 100644 --- a/src/zkevm_specs/evm/main.py +++ b/src/zkevm_specs/evm/main.py @@ -7,6 +7,7 @@ push, jump, jumpi, + coinbase, ) from .execution_state import ExecutionState from .instruction import Instruction @@ -48,6 +49,8 @@ def verify_step( jump(instruction) elif instruction.curr.execution_state == ExecutionState.JUMPI: jumpi(instruction) + elif instruction.curr.execution_state == ExecutionState.COINBASE: + coinbase(instruction) # Error cases else: raise NotImplementedError diff --git a/tests/evm/test_coinbase.py b/tests/evm/test_coinbase.py new file mode 100644 index 000000000..99cb51938 --- /dev/null +++ b/tests/evm/test_coinbase.py @@ -0,0 +1,70 @@ +import pytest + +from typing import Optional +from zkevm_specs.evm import ( + ExecutionState, + StepState, + Opcode, + verify_steps, + Tables, + RWTableTag, + RW, + Block, + Bytecode, +) +from zkevm_specs.util import hex_to_word, rand_bytes, RLCStore + + +TESTING_DATA = ((Opcode.COINBASE, hex_to_word("030201")),) + + +@pytest.mark.parametrize("opcode, address", TESTING_DATA) +def test_coinbase(opcode: Opcode, address: bytes): + rlc_store = RLCStore() + + coinbase_address = rlc_store.to_rlc(address) + + bytecode = Bytecode(f"{opcode.hex()}00") + bytecode_hash = rlc_store.to_rlc(bytecode.hash, 32) + # block = Block(coinbase_address, int(15e6), 10, 0, 0, int(1e9), []) + block = Block(coinbase_address) + tables = Tables( + block_table=set(block.table_assignments(rlc_store)), + tx_table=set(), + bytecode_table=set(bytecode.table_assignments(rlc_store)), + rw_table=set( + [ + (9, RW.Write, RWTableTag.Stack, 1, 1023, coinbase_address, 0, 0), + ] + ), + ) + + verify_steps( + rlc_store=rlc_store, + block=block, + tables=tables, + steps=[ + StepState( + execution_state=ExecutionState.COINBASE, + rw_counter=9, + call_id=1, + is_root=True, + is_create=False, + opcode_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, + opcode_source=bytecode_hash, + program_counter=1, + stack_pointer=1023, + gas_left=0, + ), + ], + ) From e414869f2f123b43f5230cff6682a1870dccdf81 Mon Sep 17 00:00:00 2001 From: Dream Wu Date: Wed, 29 Dec 2021 14:25:52 +0800 Subject: [PATCH 02/10] remove '/' --- specs/opcode/41COINBASE.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/opcode/41COINBASE.md b/specs/opcode/41COINBASE.md index 6c7a37a18..4c4bb91f9 100644 --- a/specs/opcode/41COINBASE.md +++ b/specs/opcode/41COINBASE.md @@ -18,23 +18,23 @@ then push the `address` to the stack. ## Constraints 1. opId = 0x41 -2. state transition:\ - gc + 1 ( 1 stack write)\ - stack_pointer - 1 - pc + 1\ +2. state transition: + gc + 1 ( 1 stack write) + stack_pointer - 1 + pc + 1 gas + 2 3. lookups: 2 `address` is on the top of stack `address` is in block context table -5. others: +4. others: `address` is 20 bytes length ## Exceptions -1. gas out:\ +1. gas out: remaining gas is not enough -2. stack overflow:\ +2. stack overflow: stack is full, stack pointer = 0 ## Code From fa9f6c8c594ae0f57dd99c3b05ffc5c8b02bfd0c Mon Sep 17 00:00:00 2001 From: Dream Wu Date: Thu, 30 Dec 2021 15:49:03 +0800 Subject: [PATCH 03/10] some minor fix --- specs/opcode/41COINBASE.md | 2 -- src/zkevm_specs/evm/typing.py | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/specs/opcode/41COINBASE.md b/specs/opcode/41COINBASE.md index 4c4bb91f9..a649727bc 100644 --- a/specs/opcode/41COINBASE.md +++ b/specs/opcode/41COINBASE.md @@ -26,7 +26,6 @@ then push the `address` to the stack. 3. lookups: 2 `address` is on the top of stack `address` is in block context table - 4. others: `address` is 20 bytes length @@ -38,5 +37,4 @@ then push the `address` to the stack. stack is full, stack pointer = 0 ## Code - Refer to src/zkevm_specs/evm/execution/coinbase.py diff --git a/src/zkevm_specs/evm/typing.py b/src/zkevm_specs/evm/typing.py index d6456ed35..dff4214bf 100644 --- a/src/zkevm_specs/evm/typing.py +++ b/src/zkevm_specs/evm/typing.py @@ -9,7 +9,7 @@ class Block: coinbase: U160 gas_limit: U64 block_number: U256 - time: U256 + time: U64 difficulty: U256 base_fee: U256 @@ -22,7 +22,7 @@ def __init__( coinbase: U160 = 0x10, gas_limit: U64 = int(15e6), block_number: U256 = 0, - time: U256 = 0, + time: U64 = 0, difficulty: U256 = 0, base_fee: U256 = int(1e9), history_hashes: Sequence[U256] = [], From fb52f8211cccd994133bbe8833076551e1a60288 Mon Sep 17 00:00:00 2001 From: Haichen Shen Date: Thu, 30 Dec 2021 12:00:24 -0800 Subject: [PATCH 04/10] tweak doc --- specs/opcode/41COINBASE.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/specs/opcode/41COINBASE.md b/specs/opcode/41COINBASE.md index a649727bc..e93918bb2 100644 --- a/specs/opcode/41COINBASE.md +++ b/specs/opcode/41COINBASE.md @@ -11,30 +11,30 @@ then push the `address` to the stack. ## Circuit behavior -1. construct block context table +1. construct block context table 2. do bussmapping lookup for stack write operation 3. other implicit check: bytes length ## Constraints 1. opId = 0x41 -2. state transition: - gc + 1 ( 1 stack write) - stack_pointer - 1 - pc + 1 +2. state transition: + gc + 1 (1 stack write) + stack_pointer - 1 + pc + 1 gas + 2 -3. lookups: 2 - `address` is on the top of stack - `address` is in block context table -4. others: +3. lookups: 2 + `address` is on the top of stack + `address` is in the block context table +4. others: `address` is 20 bytes length ## Exceptions -1. gas out: +1. gas out: remaining gas is not enough -2. stack overflow: +2. stack overflow: stack is full, stack pointer = 0 ## Code -Refer to src/zkevm_specs/evm/execution/coinbase.py +Please refer to `src/zkevm_specs/evm/execution/coinbase.py`. From c23a710a336a2f2c67eeefcaf932a76ba7d3d09a Mon Sep 17 00:00:00 2001 From: Haichen Shen Date: Mon, 3 Jan 2022 15:15:40 -0800 Subject: [PATCH 05/10] fix rebase error --- tests/evm/test_coinbase.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/evm/test_coinbase.py b/tests/evm/test_coinbase.py index 99cb51938..d2598bc41 100644 --- a/tests/evm/test_coinbase.py +++ b/tests/evm/test_coinbase.py @@ -41,7 +41,6 @@ def test_coinbase(opcode: Opcode, address: bytes): verify_steps( rlc_store=rlc_store, - block=block, tables=tables, steps=[ StepState( From 1830cacc046d30dc82f823d4c30f822b31842690 Mon Sep 17 00:00:00 2001 From: Haichen Shen Date: Mon, 3 Jan 2022 15:17:28 -0800 Subject: [PATCH 06/10] lint --- src/zkevm_specs/evm/execution/block_coinbase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zkevm_specs/evm/execution/block_coinbase.py b/src/zkevm_specs/evm/execution/block_coinbase.py index bba01168e..e1160ac9a 100644 --- a/src/zkevm_specs/evm/execution/block_coinbase.py +++ b/src/zkevm_specs/evm/execution/block_coinbase.py @@ -8,7 +8,7 @@ def coinbase(instruction: Instruction): instruction.constrain_equal(opcode, Opcode.COINBASE) address = instruction.stack_push() # in real circuit also check address raw data is 160 bit length (20 bytes) - # check block table for coinbase address + # check block table for coinbase address instruction.constrain_equal(address, instruction.block_lookup(BlockContextFieldTag.Coinbase)) From 1789e74d7e69b75614e267a7e2d43394b925d881 Mon Sep 17 00:00:00 2001 From: Haichen Shen Date: Mon, 3 Jan 2022 15:18:03 -0800 Subject: [PATCH 07/10] lint --- src/zkevm_specs/evm/execution/block_coinbase.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/zkevm_specs/evm/execution/block_coinbase.py b/src/zkevm_specs/evm/execution/block_coinbase.py index e1160ac9a..7889ec5c1 100644 --- a/src/zkevm_specs/evm/execution/block_coinbase.py +++ b/src/zkevm_specs/evm/execution/block_coinbase.py @@ -9,8 +9,7 @@ def coinbase(instruction: Instruction): address = instruction.stack_push() # in real circuit also check address raw data is 160 bit length (20 bytes) # check block table for coinbase address - instruction.constrain_equal(address, - instruction.block_lookup(BlockContextFieldTag.Coinbase)) + instruction.constrain_equal(address, instruction.block_lookup(BlockContextFieldTag.Coinbase)) instruction.constrain_same_context_state_transition( opcode, From da686faf9a8170d2fc708b7b7a24e724968c3938 Mon Sep 17 00:00:00 2001 From: Haichen Shen Date: Mon, 3 Jan 2022 15:21:16 -0800 Subject: [PATCH 08/10] update doc --- specs/opcode/41COINBASE.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/specs/opcode/41COINBASE.md b/specs/opcode/41COINBASE.md index e93918bb2..2f23054c9 100644 --- a/specs/opcode/41COINBASE.md +++ b/specs/opcode/41COINBASE.md @@ -18,23 +18,22 @@ then push the `address` to the stack. ## Constraints 1. opId = 0x41 -2. state transition: - gc + 1 (1 stack write) - stack_pointer - 1 - pc + 1 - gas + 2 -3. lookups: 2 - `address` is on the top of stack - `address` is in the block context table -4. others: - `address` is 20 bytes length +2. State transition: + - gc + 1 (1 stack write) + - stack_pointer - 1 + - pc + 1 + - gas + 2 +3. Lookups: 2 + - `address` is on the top of stack + - `address` is in the block context table +4. Others: + - `address` is 20 bytes length ## Exceptions -1. gas out: - remaining gas is not enough -2. stack overflow: - stack is full, stack pointer = 0 +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/coinbase.py`. From ffb6e7413f1b5bbe5d0017b1a01932e0d7810bef Mon Sep 17 00:00:00 2001 From: DreamWuGit Date: Thu, 6 Jan 2022 09:55:10 +0800 Subject: [PATCH 09/10] Apply suggestions from code review Co-authored-by: Chih Cheng Liang --- specs/opcode/41COINBASE.md | 2 +- tests/evm/test_coinbase.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/opcode/41COINBASE.md b/specs/opcode/41COINBASE.md index 2f23054c9..7ec0cade6 100644 --- a/specs/opcode/41COINBASE.md +++ b/specs/opcode/41COINBASE.md @@ -12,7 +12,7 @@ then push the `address` to the stack. ## Circuit behavior 1. construct block context table -2. do bussmapping lookup for stack write operation +2. do busmapping lookup for stack write operation 3. other implicit check: bytes length ## Constraints diff --git a/tests/evm/test_coinbase.py b/tests/evm/test_coinbase.py index d2598bc41..0eac71476 100644 --- a/tests/evm/test_coinbase.py +++ b/tests/evm/test_coinbase.py @@ -26,7 +26,6 @@ def test_coinbase(opcode: Opcode, address: bytes): bytecode = Bytecode(f"{opcode.hex()}00") bytecode_hash = rlc_store.to_rlc(bytecode.hash, 32) - # block = Block(coinbase_address, int(15e6), 10, 0, 0, int(1e9), []) block = Block(coinbase_address) tables = Tables( block_table=set(block.table_assignments(rlc_store)), From 164f7de968d6f5ca1c776edaff2ab13d0a05b2fc Mon Sep 17 00:00:00 2001 From: Dream Wu Date: Wed, 12 Jan 2022 18:14:37 +0800 Subject: [PATCH 10/10] change to use raw value into block --- src/zkevm_specs/evm/execution/block_coinbase.py | 5 ++++- tests/evm/test_coinbase.py | 13 ++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/zkevm_specs/evm/execution/block_coinbase.py b/src/zkevm_specs/evm/execution/block_coinbase.py index 7889ec5c1..3b47cdc28 100644 --- a/src/zkevm_specs/evm/execution/block_coinbase.py +++ b/src/zkevm_specs/evm/execution/block_coinbase.py @@ -9,7 +9,10 @@ def coinbase(instruction: Instruction): address = instruction.stack_push() # in real circuit also check address raw data is 160 bit length (20 bytes) # check block table for coinbase address - instruction.constrain_equal(address, instruction.block_lookup(BlockContextFieldTag.Coinbase)) + instruction.constrain_equal( + address, + instruction.bytes_to_rlc(instruction.int_to_bytes(instruction.block_lookup(BlockContextFieldTag.Coinbase), 20)), + ) instruction.constrain_same_context_state_transition( opcode, diff --git a/tests/evm/test_coinbase.py b/tests/evm/test_coinbase.py index 0eac71476..e82f43995 100644 --- a/tests/evm/test_coinbase.py +++ b/tests/evm/test_coinbase.py @@ -1,6 +1,5 @@ import pytest -from typing import Optional from zkevm_specs.evm import ( ExecutionState, StepState, @@ -12,28 +11,28 @@ Block, Bytecode, ) -from zkevm_specs.util import hex_to_word, rand_bytes, RLCStore +from zkevm_specs.util import RLCStore, U160 -TESTING_DATA = ((Opcode.COINBASE, hex_to_word("030201")),) +TESTING_DATA = ((Opcode.COINBASE, 0x030201),) @pytest.mark.parametrize("opcode, address", TESTING_DATA) -def test_coinbase(opcode: Opcode, address: bytes): +def test_coinbase(opcode: Opcode, address: U160): rlc_store = RLCStore() - coinbase_address = rlc_store.to_rlc(address) + coinbase_rlc = rlc_store.to_rlc(address.to_bytes(20, "little")) bytecode = Bytecode(f"{opcode.hex()}00") bytecode_hash = rlc_store.to_rlc(bytecode.hash, 32) - block = Block(coinbase_address) + block = Block(address) tables = Tables( block_table=set(block.table_assignments(rlc_store)), tx_table=set(), bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Write, RWTableTag.Stack, 1, 1023, coinbase_address, 0, 0), + (9, RW.Write, RWTableTag.Stack, 1, 1023, coinbase_rlc, 0, 0), ] ), )