From 00032c9b2f25c756e69f5e83015d37770203edc0 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Sat, 9 Apr 2022 10:47:47 +0800 Subject: [PATCH 1/2] fix: read from caller's memory for internal call --- specs/opcode/37CALLDATACOPY.md | 3 ++- specs/opcode/CopyToMemory.md | 6 +++--- src/zkevm_specs/evm/execution/calldatacopy.py | 7 ++++--- src/zkevm_specs/evm/execution/memory_copy.py | 6 +++--- src/zkevm_specs/evm/step.py | 6 +++--- tests/evm/test_calldatacopy.py | 16 +++++++++++----- 6 files changed, 26 insertions(+), 18 deletions(-) diff --git a/specs/opcode/37CALLDATACOPY.md b/specs/opcode/37CALLDATACOPY.md index ab32488d2..257829547 100644 --- a/specs/opcode/37CALLDATACOPY.md +++ b/specs/opcode/37CALLDATACOPY.md @@ -37,10 +37,11 @@ copying data to the memory if `length > 0`. - `memory_offset` is at the top of the stack - `data_offset` is at the second position of the stack - `length` is at the third position of the stack - - `tx_id` is in the rw table (call context) - for root calls (`is_root = 1`): + - `tx_id` is in the rw table (call context) - `call_data_length` is in the tx table - for internal calls (`is_root = 0`): + - `caller_id` is in the rw table (call context) - `call_data_length` is in the rw table (call context) - `call_data_offset` is in the rw table (call context) diff --git a/specs/opcode/CopyToMemory.md b/specs/opcode/CopyToMemory.md index f3fbf76b2..cb0ecf975 100644 --- a/specs/opcode/CopyToMemory.md +++ b/specs/opcode/CopyToMemory.md @@ -38,10 +38,10 @@ Define two auxiliary variables: 2. Lookups: nbytes_read + nbytes_written - from tx: - `nbytes_read` lookups from tx context table - - `nbytes_written` lookups from rw table (memory write) + - `nbytes_written` lookups from rw table (memory write to call_id) - from memory: - - `nbytes_read` lookups from rw table (memory read) - - `nbytes_written` lookups from rw table (memory write) + - `nbytes_read` lookups from rw table (memory read from caller_id) + - `nbytes_written` lookups from rw table (memory write to call_id) ## Exceptions diff --git a/src/zkevm_specs/evm/execution/calldatacopy.py b/src/zkevm_specs/evm/execution/calldatacopy.py index be3b98f67..d87dbf055 100644 --- a/src/zkevm_specs/evm/execution/calldatacopy.py +++ b/src/zkevm_specs/evm/execution/calldatacopy.py @@ -15,11 +15,12 @@ def calldatacopy(instruction: Instruction): memory_offset, length = instruction.memory_offset_and_length(memory_offset_word, length_word) data_offset = instruction.rlc_to_fq(data_offset_word, N_BYTES_MEMORY_ADDRESS) - tx_id = instruction.call_context_lookup(CallContextFieldTag.TxId, RW.Read) if instruction.curr.is_root: - call_data_length = instruction.tx_context_lookup(tx_id, TxContextFieldTag.CallDataLength) + src_id = instruction.call_context_lookup(CallContextFieldTag.TxId, RW.Read) + call_data_length = instruction.tx_context_lookup(src_id, TxContextFieldTag.CallDataLength) call_data_offset: Expression = FQ.zero() else: + src_id = instruction.call_context_lookup(CallContextFieldTag.CallerId, RW.Read) call_data_length = instruction.call_context_lookup( CallContextFieldTag.CallDataLength, RW.Read ) @@ -43,7 +44,7 @@ def calldatacopy(instruction: Instruction): next_aux.src_addr_end, call_data_length.expr() + call_data_offset ) instruction.constrain_equal(next_aux.from_tx, FQ(instruction.curr.is_root)) - instruction.constrain_equal(next_aux.tx_id, tx_id) + instruction.constrain_equal(next_aux.src_id, src_id) instruction.constrain_equal(next_aux.bytes_left, length) instruction.step_state_transition_in_same_context( diff --git a/src/zkevm_specs/evm/execution/memory_copy.py b/src/zkevm_specs/evm/execution/memory_copy.py index 7cac7f618..26cd9476e 100644 --- a/src/zkevm_specs/evm/execution/memory_copy.py +++ b/src/zkevm_specs/evm/execution/memory_copy.py @@ -18,9 +18,9 @@ def copy_to_memory(instruction: Instruction): if buffer_reader.read_flag(i) == 0: byte: Expression = FQ(0) elif aux.from_tx == 1: - byte = instruction.tx_calldata_lookup(aux.tx_id, aux.src_addr + i) + byte = instruction.tx_calldata_lookup(aux.src_id, aux.src_addr + i) else: - byte = instruction.memory_lookup(RW.Read, aux.src_addr + i) + byte = instruction.memory_lookup(RW.Read, aux.src_addr + i, call_id=aux.src_id) buffer_reader.constrain_byte(i, byte) if buffer_reader.has_data(i) == 1: instruction.constrain_equal(byte, instruction.memory_lookup(RW.Write, aux.dst_addr + i)) @@ -42,7 +42,7 @@ def copy_to_memory(instruction: Instruction): instruction.constrain_equal(next_aux.bytes_left + copied_bytes, aux.bytes_left) instruction.constrain_equal(next_aux.src_addr_end, aux.src_addr_end) instruction.constrain_equal(next_aux.from_tx, aux.from_tx) - instruction.constrain_equal(next_aux.tx_id, aux.tx_id) + instruction.constrain_equal(next_aux.src_id, aux.src_id) instruction.constrain_step_state_transition( rw_counter=Transition.delta(instruction.rw_counter_offset), diff --git a/src/zkevm_specs/evm/step.py b/src/zkevm_specs/evm/step.py index 7780a40fd..589d92954 100644 --- a/src/zkevm_specs/evm/step.py +++ b/src/zkevm_specs/evm/step.py @@ -85,7 +85,7 @@ class CopyToMemoryAuxData: bytes_left: FQ src_addr_end: FQ from_tx: FQ - tx_id: FQ + src_id: FQ def __init__( self, @@ -94,14 +94,14 @@ def __init__( bytes_left: int, src_addr_end: int, from_tx: bool, - tx_id: int, + src_id: int, ): self.src_addr = FQ(src_addr) self.dst_addr = FQ(dst_addr) self.bytes_left = FQ(bytes_left) self.src_addr_end = FQ(src_addr_end) self.from_tx = FQ(from_tx) - self.tx_id = FQ(tx_id) + self.src_id = FQ(src_id) class CopyToLogAuxData: diff --git a/tests/evm/test_calldatacopy.py b/tests/evm/test_calldatacopy.py index f9b1e31be..8fb23c53b 100644 --- a/tests/evm/test_calldatacopy.py +++ b/tests/evm/test_calldatacopy.py @@ -28,6 +28,7 @@ TX_ID = 13 +CALLER_ID = 0 CALL_ID = 1 TESTING_DATA = ( # simple cases @@ -70,7 +71,7 @@ def make_copy_step( src_addr_end=src_addr_end, bytes_left=bytes_left, from_tx=from_tx, - tx_id=TX_ID, + src_id=TX_ID if from_tx else CALLER_ID, ) step = StepState( execution_state=ExecutionState.CopyToMemory, @@ -89,7 +90,7 @@ def make_copy_step( for i in range(num_bytes): byte = buffer_map[src_addr + i] if src_addr + i < src_addr_end else 0 if not from_tx and src_addr + i < src_addr_end: - rw_dictionary.memory_read(CALL_ID, src_addr + i, byte) + rw_dictionary.memory_read(CALLER_ID, src_addr + i, byte) rw_dictionary.memory_write(CALL_ID, dst_addr + i, byte) return step @@ -205,12 +206,17 @@ def test_calldatacopy( .stack_read(CALL_ID, 1021, memory_offset_rlc) .stack_read(CALL_ID, 1022, data_offset_rlc) .stack_read(CALL_ID, 1023, length_rlc) - .call_context_read(CALL_ID, CallContextFieldTag.TxId, TX_ID) ) - if not from_tx: + if from_tx: + rw_dictionary.call_context_read(CALL_ID, CallContextFieldTag.TxId, TX_ID) + else: rw_dictionary.call_context_read( + CALL_ID, CallContextFieldTag.CallerId, CALLER_ID + ).call_context_read( CALL_ID, CallContextFieldTag.CallDataLength, call_data_length - ).call_context_read(CALL_ID, CallContextFieldTag.CallDataOffset, call_data_offset) + ).call_context_read( + CALL_ID, CallContextFieldTag.CallDataOffset, call_data_offset + ) new_steps = make_copy_steps( call_data, From b1e8a3ba80be7f5780e0d4ef41c1f509f86e3be4 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Mon, 11 Apr 2022 11:49:30 +0800 Subject: [PATCH 2/2] fix: call data length looked up from rw table call context --- specs/opcode/37CALLDATACOPY.md | 6 +++--- src/zkevm_specs/evm/execution/calldatacopy.py | 4 +++- tests/evm/test_calldatacopy.py | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/specs/opcode/37CALLDATACOPY.md b/specs/opcode/37CALLDATACOPY.md index 257829547..81b8236b2 100644 --- a/specs/opcode/37CALLDATACOPY.md +++ b/specs/opcode/37CALLDATACOPY.md @@ -25,8 +25,8 @@ copying data to the memory if `length > 0`. 1. opId = 0x37 2. State transition: - rw_counter - - +4 for root calls (3 stack read, 1 call context read) - - +6 for internal calls (3 stack read, 3 call context read) + - +5 for root calls (3 stack read, 2 call context reads) + - +6 for internal calls (3 stack read, 3 call context reads) - stack_pointer + 3 - pc + 1 - gas + 3 + dynamic cost (memory expansion and copier cost when `length > 0`) @@ -39,7 +39,7 @@ copying data to the memory if `length > 0`. - `length` is at the third position of the stack - for root calls (`is_root = 1`): - `tx_id` is in the rw table (call context) - - `call_data_length` is in the tx table + - `call_data_length` is in the rw table (call context) - for internal calls (`is_root = 0`): - `caller_id` is in the rw table (call context) - `call_data_length` is in the rw table (call context) diff --git a/src/zkevm_specs/evm/execution/calldatacopy.py b/src/zkevm_specs/evm/execution/calldatacopy.py index d87dbf055..eb3152345 100644 --- a/src/zkevm_specs/evm/execution/calldatacopy.py +++ b/src/zkevm_specs/evm/execution/calldatacopy.py @@ -17,7 +17,9 @@ def calldatacopy(instruction: Instruction): if instruction.curr.is_root: src_id = instruction.call_context_lookup(CallContextFieldTag.TxId, RW.Read) - call_data_length = instruction.tx_context_lookup(src_id, TxContextFieldTag.CallDataLength) + call_data_length = instruction.call_context_lookup( + CallContextFieldTag.CallDataLength, RW.Read + ) call_data_offset: Expression = FQ.zero() else: src_id = instruction.call_context_lookup(CallContextFieldTag.CallerId, RW.Read) diff --git a/tests/evm/test_calldatacopy.py b/tests/evm/test_calldatacopy.py index 8fb23c53b..b588fca8f 100644 --- a/tests/evm/test_calldatacopy.py +++ b/tests/evm/test_calldatacopy.py @@ -208,7 +208,9 @@ def test_calldatacopy( .stack_read(CALL_ID, 1023, length_rlc) ) if from_tx: - rw_dictionary.call_context_read(CALL_ID, CallContextFieldTag.TxId, TX_ID) + rw_dictionary.call_context_read(CALL_ID, CallContextFieldTag.TxId, TX_ID).call_context_read( + CALL_ID, CallContextFieldTag.CallDataLength, call_data_length + ) else: rw_dictionary.call_context_read( CALL_ID, CallContextFieldTag.CallerId, CALLER_ID