Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Entrypoint for EVM circuit and specification for BEGIN_TX #52

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3e4aa3d
feat: evm circuit with almost finished CALL
han0110 Oct 8, 2021
647d932
feat: finish value transfer in BEGIN_TX and CALL
han0110 Oct 9, 2021
0044dac
feat: complete opcode CALL except precompile
han0110 Oct 13, 2021
af8012e
feat: refactor and add some error case verification
han0110 Oct 14, 2021
f409925
feat: make up all opcode and add push case
han0110 Oct 14, 2021
ee9d018
feat: add test_add to test ExecutionResult.ADD
han0110 Oct 15, 2021
840f6c9
feat: add test_call to test ExecutionResult.CALL with callee being co…
han0110 Oct 17, 2021
77713cb
feat: add OpcodeInfo
han0110 Oct 18, 2021
5455be9
feat: add test_push to test ExecutionResult.PUSH
han0110 Oct 18, 2021
06518c9
feat: refactor evm into modules and move tests into pytest directory
han0110 Oct 18, 2021
0e1f4d2
feat: add test_begin_tx to test ExecutionResult.BEGIN_TX with callee …
han0110 Oct 19, 2021
d6f0d5e
refactor: simplify test_call's call_lookup for next call
han0110 Oct 20, 2021
88fa749
feat: refactor with comment to explain classes
han0110 Oct 21, 2021
2117c26
feat: explain more on CallState
han0110 Oct 21, 2021
7a7d559
chore: tweak type and enum order
han0110 Oct 22, 2021
a2cc202
chore: rename *_end_of_revert to *_end_of_reversion
han0110 Oct 25, 2021
32af917
feat: explain more on reversion and only write TxRefund and AccountDe…
han0110 Oct 27, 2021
6f1915b
fix: assert enough allocations and fix verification of PUSH* opcode i…
han0110 Oct 29, 2021
8e60571
fix: add more comment on call_id propagation and fix comment in error…
han0110 Oct 29, 2021
f0aae07
fix: add assertion message on the limit num of bytes of le_to_int
han0110 Oct 31, 2021
0475e24
feat: merge call context in call_table to rw_table for simplicity
han0110 Oct 31, 2021
9b1ccdd
fix: range lookup depth with minus 1 since depth starts from 1
han0110 Nov 1, 2021
5d8832e
feat: rewrite step by instruction without requiring explicitly witnes…
han0110 Nov 26, 2021
c402f3b
feat: rewrite begin_tx with instruction
han0110 Nov 26, 2021
f0b5316
chore: remove partial implemented execution result for further PR
han0110 Nov 26, 2021
55358eb
feat: improve mul_word_by_u64
han0110 Nov 27, 2021
7697e1c
fix: fix rw_counter to Transition.delta(16) and adjust order of read/…
han0110 Dec 2, 2021
db85aa2
feat: add failed transaction test case
han0110 Dec 3, 2021
4592064
chore: mark root creation call opcode_lookup as NotImplemented like c…
han0110 Dec 4, 2021
a9a99b6
feat: add is_code annotation as in circuit implementation
han0110 Dec 4, 2021
9feba12
chore: rename classes and tags to match circuit implementation
han0110 Dec 5, 2021
0e5151d
fix: make fmt
han0110 Dec 8, 2021
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
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package_dir =
= src
packages = find:
python_requires = >=3.6
install_requires =
pycryptodome==3.11.0

[options.packages.find]
where = src
Expand Down
2 changes: 2 additions & 0 deletions src/zkevm_specs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from . import encoding
from . import evm
from . import opcode
from . import util
8 changes: 8 additions & 0 deletions src/zkevm_specs/evm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .execution import *
from .execution_state import *
from .main import *
from .opcode import *
from .precompiled import *
from .step import *
from .table import *
from .typing import *
7 changes: 7 additions & 0 deletions src/zkevm_specs/evm/execution/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .begin_tx import *

# Opcode's successful cases
from .add import *
from .push import *

# Error cases
24 changes: 24 additions & 0 deletions src/zkevm_specs/evm/execution/add.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from ..instruction import Instruction, Transition
from ..opcode import Opcode


def add(instruction: Instruction):
opcode = instruction.opcode_lookup(True)

is_sub, _ = instruction.pair_select(opcode, Opcode.SUB, Opcode.ADD)

a = instruction.stack_pop()
b = instruction.stack_pop()
c = instruction.stack_push()

instruction.constrain_equal(
instruction.add_word(instruction.select(is_sub, c, a), b)[0],
instruction.select(is_sub, a, c),
)

instruction.constrain_same_context_state_transition(
opcode,
rw_counter=Transition.delta(3),
program_counter=Transition.delta(1),
stack_pointer=Transition.delta(1),
)
89 changes: 89 additions & 0 deletions src/zkevm_specs/evm/execution/begin_tx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from ..instruction import Instruction, Transition
from ..table import CallContextFieldTag, TxContextFieldTag, RW, AccountFieldTag
from ..precompiled import PrecompiledAddress


def begin_tx(instruction: Instruction, is_first_step: bool = False):
instruction.constrain_equal(instruction.curr.call_id, instruction.curr.rw_counter)

tx_id = instruction.call_context_lookup(CallContextFieldTag.TxId)
rw_counter_end_of_reversion = instruction.call_context_lookup(CallContextFieldTag.RWCounterEndOfReversion)
is_persistent = instruction.call_context_lookup(CallContextFieldTag.IsPersistent)

if is_first_step:
instruction.constrain_equal(instruction.curr.rw_counter, 1)
instruction.constrain_equal(tx_id, 1)

tx_caller_address = instruction.tx_lookup(tx_id, TxContextFieldTag.CallerAddress)
tx_callee_address = instruction.tx_lookup(tx_id, TxContextFieldTag.CalleeAddress)
tx_is_create = instruction.tx_lookup(tx_id, TxContextFieldTag.IsCreate)
tx_value = instruction.tx_lookup(tx_id, TxContextFieldTag.Value)
tx_call_data_length = instruction.tx_lookup(tx_id, TxContextFieldTag.CallDataLength)

# Verify nonce
tx_nonce = instruction.tx_lookup(tx_id, TxContextFieldTag.Nonce)
nonce, nonce_prev = instruction.account_write(tx_caller_address, AccountFieldTag.Nonce)
instruction.constrain_equal(tx_nonce, nonce_prev)
instruction.constrain_equal(nonce, nonce_prev + 1)

# TODO: Implement EIP 1559 (currently this assumes gas_fee_cap <= basefee + gas_tip_cap)
# Calculate gas fee
tx_gas = instruction.tx_lookup(tx_id, TxContextFieldTag.Gas)
tx_gas_fee_cap = instruction.tx_lookup(tx_id, TxContextFieldTag.GasFeeCap)
gas_fee, carry = instruction.mul_word_by_u64(tx_gas_fee_cap, tx_gas)
instruction.constrain_zero(carry)

# TODO: Use intrinsic gas (EIP 2028, 2930)
gas_left = tx_gas - (53000 if tx_is_create else 21000)
instruction.int_to_bytes(gas_left, 8)

# Prepare access list of caller and callee
instruction.constrain_equal(instruction.add_account_to_access_list(tx_id, tx_caller_address), 1)
instruction.constrain_equal(instruction.add_account_to_access_list(tx_id, tx_callee_address), 1)

# Verify transfer
instruction.constrain_transfer(
tx_caller_address,
tx_callee_address,
tx_value,
gas_fee=gas_fee,
is_persistent=is_persistent,
rw_counter_end_of_reversion=rw_counter_end_of_reversion,
)

if tx_is_create:
# TODO: Verify receiver address
# TODO: Set opcode_source to tx_id
raise NotImplementedError
elif tx_callee_address in list(PrecompiledAddress):
# TODO: Handle precompile
raise NotImplementedError
else:
code_hash, _ = instruction.account_read(tx_callee_address, AccountFieldTag.CodeHash)

# Setup next call's context
# Note that:
# - CallerCallId, ReturnDataOffset, ReturnDataLength, Result
# should never be used in root call, so unnecessary to check
# - TxId is propagated from previous step or constraint to 1 if is_first_step
# - IsPersistent will be verified in the end of tx
for (tag, value) in [
(CallContextFieldTag.Depth, 1),
(CallContextFieldTag.CallerAddress, tx_caller_address),
(CallContextFieldTag.CalleeAddress, tx_callee_address),
(CallContextFieldTag.CallDataOffset, 0),
(CallContextFieldTag.CallDataLength, tx_call_data_length),
(CallContextFieldTag.Value, tx_value),
(CallContextFieldTag.IsStatic, False),
]:
instruction.constrain_equal(instruction.call_context_lookup(tag), value)

instruction.constrain_new_context_state_transition(
rw_counter=Transition.delta(16),
call_id=Transition.persistent(),
is_root=Transition.to(True),
is_create=Transition.to(False),
opcode_source=Transition.to(code_hash),
gas_left=Transition.to(gas_left),
state_write_counter=Transition.to(2),
)
26 changes: 26 additions & 0 deletions src/zkevm_specs/evm/execution/push.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from ..instruction import Instruction, Transition
from ..opcode import Opcode


def push(instruction: Instruction):
opcode = instruction.opcode_lookup(True)
num_pushed = opcode - Opcode.PUSH1 + 1
num_additional_pushed = num_pushed - 1

value = instruction.stack_push()
value_bytes = instruction.rlc_to_bytes(value, 32)
selectors = instruction.continuous_selectors(num_additional_pushed, 31)

for idx in range(32):
index = instruction.curr.program_counter + num_pushed - idx
if idx == 0 or selectors[idx - 1]:
instruction.constrain_equal(value_bytes[idx], instruction.opcode_lookup_at(index, False))
else:
instruction.constrain_zero(value_bytes[idx])

instruction.constrain_same_context_state_transition(
opcode,
rw_counter=Transition.delta(1),
program_counter=Transition.delta(1 + num_pushed),
stack_pointer=Transition.delta(-1),
)
Loading