From 0b939b92876205e62dd3ca62b688d55c9355a5a7 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Fri, 14 Jan 2022 17:03:35 +0800 Subject: [PATCH 01/37] init: increase RwTable size --- src/zkevm_specs/evm/instruction.py | 19 ++++++------------- src/zkevm_specs/evm/table.py | 24 +++++++++++++----------- src/zkevm_specs/util/typing.py | 1 + 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index c8bf630e5..3802223fa 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -2,7 +2,7 @@ from enum import IntEnum, auto from typing import Optional, Sequence, Tuple, Union -from ..util import Array4, Array8, linear_combine, RLCStore, MAX_N_BYTES, N_BYTES_GAS +from ..util import Array4, Array10, linear_combine, RLCStore, MAX_N_BYTES, N_BYTES_GAS from .opcode import Opcode from .step import StepState from .table import ( @@ -259,7 +259,7 @@ def opcode_lookup_at(self, index: int, is_code: bool) -> int: else: return self.bytecode_lookup(self.curr.opcode_source, index, is_code) - def rw_lookup(self, rw: RW, tag: RWTableTag, inputs: Sequence[int], rw_counter: Optional[int] = None) -> Array8: + def rw_lookup(self, rw: RW, tag: RWTableTag, inputs: Sequence[int], rw_counter: Optional[int] = None) -> Array10: if rw_counter is None: rw_counter = self.curr.rw_counter + self.rw_counter_offset self.rw_counter_offset += 1 @@ -271,13 +271,13 @@ def state_write_only_persistent( tag: RWTableTag, inputs: Sequence[int], is_persistent: bool, - ) -> Array8: + ) -> Array10: assert tag.write_only_persistent() if is_persistent: return self.rw_lookup(RW.Write, tag, inputs) - return 8 * [None] + return 10 * [None] def state_write_with_reversion( self, @@ -285,7 +285,7 @@ def state_write_with_reversion( inputs: Sequence[int], is_persistent: bool, rw_counter_end_of_reversion: int, - ) -> Array8: + ) -> Array10: assert tag.write_with_reversion() row = self.rw_lookup(RW.Write, tag, inputs) @@ -296,14 +296,7 @@ def state_write_with_reversion( if not is_persistent: # Swap value and value_prev inputs = list(row[3:]) - if tag == RWTableTag.TxAccessListAccount: - inputs[2], inputs[3] = inputs[3], inputs[2] - elif tag == RWTableTag.TxAccessListStorageSlot: - inputs[3], inputs[4] = inputs[4], inputs[3] - elif tag == RWTableTag.Account: - inputs[2], inputs[3] = inputs[3], inputs[2] - elif tag == RWTableTag.AccountStorage: - inputs[3], inputs[4] = inputs[4], inputs[3] + inputs[-3], inputs[-4] = inputs[-4], inputs[-3] self.rw_lookup(RW.Write, tag, inputs, rw_counter=rw_counter) return row diff --git a/src/zkevm_specs/evm/table.py b/src/zkevm_specs/evm/table.py index a970b09d2..13a566dac 100644 --- a/src/zkevm_specs/evm/table.py +++ b/src/zkevm_specs/evm/table.py @@ -1,7 +1,7 @@ from typing import Sequence, Set, Tuple from enum import IntEnum, auto -from ..util import Array3, Array4, Array8 +from ..util import Array3, Array4, Array10 from .execution_state import ExecutionState from .opcode import ( invalid_opcodes, @@ -244,20 +244,22 @@ class Tables: # Each row in RWTable contains: # - rw_counter # - is_write - # - tag - # - value1 - # - value2 - # - value3 - # - value4 - # - value5 - rw_table: Set[Array8] + # - key1 (tag) + # - key2 + # - key3 + # - key4 + # - value + # - value_prev + # - aux1 + # - aux2 + rw_table: Set[Array10] def __init__( self, block_table: Set[Array3], tx_table: Set[Array4], bytecode_table: Set[Array4], - rw_table: Set[Array8], + rw_table: Set[Array10], ) -> None: self.block_table = block_table self.tx_table = tx_table @@ -280,8 +282,8 @@ def bytecode_lookup(self, inputs: Sequence[int]) -> Array4: assert len(inputs) <= 4 return _lookup("bytecode_table", self.bytecode_table, inputs) - def rw_lookup(self, inputs: Sequence[int]) -> Array8: - assert len(inputs) <= 8 + def rw_lookup(self, inputs: Sequence[int]) -> Array10: + assert len(inputs) <= 10 return _lookup("rw_table", self.rw_table, inputs) diff --git a/src/zkevm_specs/util/typing.py b/src/zkevm_specs/util/typing.py index 370f562db..0ab5b8234 100644 --- a/src/zkevm_specs/util/typing.py +++ b/src/zkevm_specs/util/typing.py @@ -8,6 +8,7 @@ Array3 = NewType("Array3", Tuple[int, int, int]) Array4 = NewType("Array4", Tuple[int, int, int, int]) Array8 = NewType("Array8", Tuple[int, int, int, int, int, int, int, int]) +Array10 = NewType("Array10", Tuple[int, int, int, int, int, int, int, int, int, int]) Array32 = NewType( "Array32", Tuple[ From 74198e373818ef1e5d0999bb93919d811e43805d Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 17 Jan 2022 09:57:25 +0800 Subject: [PATCH 02/37] fix test except begin_tx --- tests/evm/test_add.py | 6 +++--- tests/evm/test_coinbase.py | 2 +- tests/evm/test_jump.py | 2 +- tests/evm/test_jumpi.py | 4 ++-- tests/evm/test_push.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/evm/test_add.py b/tests/evm/test_add.py index 8ba0371b8..558a33467 100644 --- a/tests/evm/test_add.py +++ b/tests/evm/test_add.py @@ -45,9 +45,9 @@ def test_add(opcode: Opcode, a_bytes: bytes, b_bytes: bytes, c_bytes: Optional[b bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Read, RWTableTag.Stack, 1, 1022, a, 0, 0), - (10, RW.Read, RWTableTag.Stack, 1, 1023, b, 0, 0), - (11, RW.Write, RWTableTag.Stack, 1, 1023, c, 0, 0), + (9, RW.Read, RWTableTag.Stack, 1, 1022, a, 0, 0, 0, 0), + (10, RW.Read, RWTableTag.Stack, 1, 1023, b, 0, 0, 0, 0), + (11, RW.Write, RWTableTag.Stack, 1, 1023, c, 0, 0, 0, 0), ] ), ) diff --git a/tests/evm/test_coinbase.py b/tests/evm/test_coinbase.py index e82f43995..b5d5ec771 100644 --- a/tests/evm/test_coinbase.py +++ b/tests/evm/test_coinbase.py @@ -32,7 +32,7 @@ def test_coinbase(opcode: Opcode, address: U160): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Write, RWTableTag.Stack, 1, 1023, coinbase_rlc, 0, 0), + (9, RW.Write, RWTableTag.Stack, 1, 1023, coinbase_rlc, 0, 0, 0, 0), ] ), ) diff --git a/tests/evm/test_jump.py b/tests/evm/test_jump.py index 8e6cb1769..e8fc0fed5 100644 --- a/tests/evm/test_jump.py +++ b/tests/evm/test_jump.py @@ -35,7 +35,7 @@ def test_jump(opcode: Opcode, dest_bytes: bytes): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Read, RWTableTag.Stack, 1, 1021, dest, 0, 0), + (9, RW.Read, RWTableTag.Stack, 1, 1021, dest, 0, 0, 0, 0), ] ), ) diff --git a/tests/evm/test_jumpi.py b/tests/evm/test_jumpi.py index 221796fee..0b59d8c95 100644 --- a/tests/evm/test_jumpi.py +++ b/tests/evm/test_jumpi.py @@ -93,8 +93,8 @@ def test_jumpi_cond_zero(opcode: Opcode, cond_bytes: bytes, dest_bytes: bytes): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Read, RWTableTag.Stack, 1, 1021, dest, 0, 0), - (10, RW.Read, RWTableTag.Stack, 1, 1022, cond, 0, 0), + (9, RW.Read, RWTableTag.Stack, 1, 1021, dest, 0, 0, 0, 0), + (10, RW.Read, RWTableTag.Stack, 1, 1022, cond, 0, 0, 0, 0), ], ), ) diff --git a/tests/evm/test_push.py b/tests/evm/test_push.py index d663a2aaf..dc171bd39 100644 --- a/tests/evm/test_push.py +++ b/tests/evm/test_push.py @@ -41,7 +41,7 @@ def test_push(opcode: Opcode, value_be_bytes: bytes): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (8, RW.Write, RWTableTag.Stack, 1, 1023, value, 0, 0), + (8, RW.Write, RWTableTag.Stack, 1, 1023, value, 0, 0, 0, 0), ] ), ) From ee16a519860542d51b800975a940b5b2f7ab319c Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 17 Jan 2022 10:26:14 +0800 Subject: [PATCH 03/37] fix test_ begin_tx --- src/zkevm_specs/evm/instruction.py | 22 +++++++++--------- tests/evm/test_begin_tx.py | 36 +++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index 3802223fa..380d3e22b 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -330,7 +330,7 @@ def account_write( RWTableTag.Account, [account_address, account_field_tag], ) - return row[5], row[6] + return row[-4], row[-3] def account_write_with_reversion( self, @@ -345,7 +345,7 @@ def account_write_with_reversion( is_persistent, rw_counter_end_of_reversion, ) - return row[5], row[6] + return row[-4], row[-3] def add_balance(self, account_address: int, values: Sequence[int]): balance, balance_prev = self.account_write(account_address, AccountFieldTag.Balance) @@ -389,7 +389,7 @@ def sub_balance_with_reversion( def account_read(self, account_address: int, account_field_tag: AccountFieldTag) -> Tuple[int, int]: row = self.rw_lookup(RW.Read, RWTableTag.Account, [account_address, account_field_tag]) - return row[5], row[6] + return row[-4], row[-3] def add_account_to_access_list( self, @@ -399,9 +399,9 @@ def add_account_to_access_list( row = self.rw_lookup( RW.Write, RWTableTag.TxAccessListAccount, - [tx_id, account_address, 1], + [tx_id, account_address, 0, 1], ) - return row[5] - row[6] + return row[-4] - row[-3] def add_account_to_access_list_with_reversion( self, @@ -412,11 +412,11 @@ def add_account_to_access_list_with_reversion( ) -> bool: row = self.state_write_with_reversion( RWTableTag.TxAccessListAccount, - [tx_id, account_address, 1], + [tx_id, account_address, 0, 1], is_persistent, rw_counter_end_of_reversion, ) - return row[5] - row[6] + return row[-4] - row[-3] def add_storage_slot_to_access_list( self, @@ -425,10 +425,10 @@ def add_storage_slot_to_access_list( storage_slot: int, ) -> bool: row = self.state_write_with_reversion( - RWTableTag.TxAccessListAccount, + RWTableTag.TxAccessListStorageSlot, [tx_id, account_address, storage_slot, 1], ) - return row[6] - row[7] + return row[-4] - row[-3] def add_storage_slot_to_access_list_with_reversion( self, @@ -439,12 +439,12 @@ def add_storage_slot_to_access_list_with_reversion( rw_counter_end_of_reversion: int, ) -> bool: row = self.state_write_with_reversion( - RWTableTag.TxAccessListAccount, + RWTableTag.TxAccessListStorageSlot, [tx_id, account_address, storage_slot, 1], is_persistent, rw_counter_end_of_reversion, ) - return row[6] - row[7] + return row[-4] - row[-3] def transfer_with_gas_fee( self, diff --git a/tests/evm/test_begin_tx.py b/tests/evm/test_begin_tx.py index 9908a97a6..2b12b9c85 100644 --- a/tests/evm/test_begin_tx.py +++ b/tests/evm/test_begin_tx.py @@ -58,7 +58,7 @@ def test_begin_tx(tx: Transaction, result: bool): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (1, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 1, 0, 0), + (1, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 1, 0, 0, 0, 0), ( 2, RW.Read, @@ -68,20 +68,24 @@ def test_begin_tx(tx: Transaction, result: bool): 0 if result else 20, 0, 0, + 0, + 0, ), - (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, result, 0, 0), - (4, RW.Write, RWTableTag.Account, tx.caller_address, AccountFieldTag.Nonce, tx.nonce + 1, tx.nonce, 0), - (5, RW.Write, RWTableTag.TxAccessListAccount, 1, tx.caller_address, 1, 0, 0), - (6, RW.Write, RWTableTag.TxAccessListAccount, 1, tx.callee_address, 1, 0, 0), + (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, result, 0, 0, 0, 0), + (4, RW.Write, RWTableTag.Account, tx.caller_address, AccountFieldTag.Nonce, 0, tx.nonce + 1, tx.nonce, 0, 0), + (5, RW.Write, RWTableTag.TxAccessListAccount, 1, tx.caller_address, 0, 1, 0, 0, 0), + (6, RW.Write, RWTableTag.TxAccessListAccount, 1, tx.callee_address, 0, 1, 0, 0, 0), ( 7, RW.Write, RWTableTag.Account, tx.caller_address, AccountFieldTag.Balance, + 0, caller_balance, caller_balance_prev, 0, + 0, ), ( 8, @@ -89,9 +93,11 @@ def test_begin_tx(tx: Transaction, result: bool): RWTableTag.Account, tx.callee_address, AccountFieldTag.Balance, + 0, callee_balance, callee_balance_prev, 0, + 0, ), ( 9, @@ -99,15 +105,17 @@ def test_begin_tx(tx: Transaction, result: bool): RWTableTag.Account, tx.callee_address, AccountFieldTag.CodeHash, + 0, bytecode_hash, bytecode_hash, 0, + 0, ), - (10, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.Depth, 1, 0, 0), - (11, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallerAddress, tx.caller_address, 0, 0), - (12, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CalleeAddress, tx.callee_address, 0, 0), - (13, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallDataOffset, 0, 0, 0), - (14, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallDataLength, len(tx.call_data), 0, 0), + (10, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.Depth, 1, 0, 0, 0, 0), + (11, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallerAddress, tx.caller_address, 0, 0, 0, 0), + (12, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CalleeAddress, tx.callee_address, 0, 0, 0, 0), + (13, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallDataOffset, 0, 0, 0, 0, 0), + (14, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallDataLength, len(tx.call_data), 0, 0, 0, 0), ( 15, RW.Read, @@ -117,8 +125,10 @@ def test_begin_tx(tx: Transaction, result: bool): rlc_store.to_rlc(tx.value, 32), 0, 0, + 0, + 0, ), - (16, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsStatic, 0, 0, 0), + (16, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsStatic, 0, 0, 0, 0, 0), ] + ( [] @@ -130,9 +140,11 @@ def test_begin_tx(tx: Transaction, result: bool): RWTableTag.Account, tx.callee_address, AccountFieldTag.Balance, + 0, callee_balance_prev, callee_balance, 0, + 0, ), ( 20, @@ -140,9 +152,11 @@ def test_begin_tx(tx: Transaction, result: bool): RWTableTag.Account, tx.caller_address, AccountFieldTag.Balance, + 0, caller_balance_prev, caller_balance, 0, + 0, ), ] ) From a2dea647eaf32582b067735306843bac1fc3dfb9 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 17 Jan 2022 10:48:02 +0800 Subject: [PATCH 04/37] clean up --- src/zkevm_specs/evm/table.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/zkevm_specs/evm/table.py b/src/zkevm_specs/evm/table.py index 13a566dac..fc186e16f 100644 --- a/src/zkevm_specs/evm/table.py +++ b/src/zkevm_specs/evm/table.py @@ -108,15 +108,8 @@ def write_with_reversion(self) -> bool: RWTableTag.TxAccessListStorageSlot, RWTableTag.Account, RWTableTag.AccountStorage, - ] - - # For state writes which don't affect future execution before reversion, we - # don't need to write them with reversion, instead we only need to write - # them (enable the lookup) when is_persistent is True. - def write_only_persistent(self) -> bool: - return self in [ - RWTableTag.TxRefund, RWTableTag.AccountDestructed, + RWTableTag.TxRefund, ] From b69f88ebe76364be22f72d0669f52bdd14fccfae Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 17 Jan 2022 10:52:00 +0800 Subject: [PATCH 05/37] lint codes --- tests/evm/test_begin_tx.py | 52 +++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/tests/evm/test_begin_tx.py b/tests/evm/test_begin_tx.py index 2b12b9c85..2c26c0f17 100644 --- a/tests/evm/test_begin_tx.py +++ b/tests/evm/test_begin_tx.py @@ -72,7 +72,18 @@ def test_begin_tx(tx: Transaction, result: bool): 0, ), (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, result, 0, 0, 0, 0), - (4, RW.Write, RWTableTag.Account, tx.caller_address, AccountFieldTag.Nonce, 0, tx.nonce + 1, tx.nonce, 0, 0), + ( + 4, + RW.Write, + RWTableTag.Account, + tx.caller_address, + AccountFieldTag.Nonce, + 0, + tx.nonce + 1, + tx.nonce, + 0, + 0, + ), (5, RW.Write, RWTableTag.TxAccessListAccount, 1, tx.caller_address, 0, 1, 0, 0, 0), (6, RW.Write, RWTableTag.TxAccessListAccount, 1, tx.callee_address, 0, 1, 0, 0, 0), ( @@ -112,10 +123,43 @@ def test_begin_tx(tx: Transaction, result: bool): 0, ), (10, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.Depth, 1, 0, 0, 0, 0), - (11, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallerAddress, tx.caller_address, 0, 0, 0, 0), - (12, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CalleeAddress, tx.callee_address, 0, 0, 0, 0), + ( + 11, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.CallerAddress, + tx.caller_address, + 0, + 0, + 0, + 0, + ), + ( + 12, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.CalleeAddress, + tx.callee_address, + 0, + 0, + 0, + 0, + ), (13, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallDataOffset, 0, 0, 0, 0, 0), - (14, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallDataLength, len(tx.call_data), 0, 0, 0, 0), + ( + 14, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.CallDataLength, + len(tx.call_data), + 0, + 0, + 0, + 0, + ), ( 15, RW.Read, From c110cb193799cf4a4fbfd73efea1c1cf85dd3878 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 17 Jan 2022 15:09:03 +0800 Subject: [PATCH 06/37] fix call_context_lookup --- src/zkevm_specs/evm/instruction.py | 2 +- tests/evm/test_begin_tx.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index 380d3e22b..0a6de00c2 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -305,7 +305,7 @@ def call_context_lookup(self, tag: CallContextFieldTag, rw: RW = RW.Read, call_i if call_id is None: call_id = self.curr.call_id - return self.rw_lookup(rw, RWTableTag.CallContext, [call_id, tag])[5] + return self.rw_lookup(rw, RWTableTag.CallContext, [call_id, tag])[-4] def stack_pop(self) -> int: stack_pointer_offset = self.stack_pointer_offset diff --git a/tests/evm/test_begin_tx.py b/tests/evm/test_begin_tx.py index 2c26c0f17..f3072d095 100644 --- a/tests/evm/test_begin_tx.py +++ b/tests/evm/test_begin_tx.py @@ -58,20 +58,20 @@ def test_begin_tx(tx: Transaction, result: bool): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (1, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 1, 0, 0, 0, 0), + (1, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, 1, 0, 0, 0), ( 2, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.RWCounterEndOfReversion, - 0 if result else 20, 0, + 0 if result else 20, 0, 0, 0, ), - (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, result, 0, 0, 0, 0), + (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), ( 4, RW.Write, @@ -122,15 +122,15 @@ def test_begin_tx(tx: Transaction, result: bool): 0, 0, ), - (10, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.Depth, 1, 0, 0, 0, 0), + (10, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.Depth, 0, 1, 0, 0, 0), ( 11, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallerAddress, - tx.caller_address, 0, + tx.caller_address, 0, 0, 0, @@ -141,8 +141,8 @@ def test_begin_tx(tx: Transaction, result: bool): RWTableTag.CallContext, 1, CallContextFieldTag.CalleeAddress, - tx.callee_address, 0, + tx.callee_address, 0, 0, 0, @@ -154,8 +154,8 @@ def test_begin_tx(tx: Transaction, result: bool): RWTableTag.CallContext, 1, CallContextFieldTag.CallDataLength, - len(tx.call_data), 0, + len(tx.call_data), 0, 0, 0, @@ -166,8 +166,8 @@ def test_begin_tx(tx: Transaction, result: bool): RWTableTag.CallContext, 1, CallContextFieldTag.Value, - rlc_store.to_rlc(tx.value, 32), 0, + rlc_store.to_rlc(tx.value, 32), 0, 0, 0, From d7d3557689554ad95f15513be54a095ea23885d9 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 17 Jan 2022 16:03:54 +0800 Subject: [PATCH 07/37] fix stack_lookup --- src/zkevm_specs/evm/instruction.py | 2 +- tests/evm/test_add.py | 6 +++--- tests/evm/test_coinbase.py | 2 +- tests/evm/test_jump.py | 2 +- tests/evm/test_jumpi.py | 8 ++++---- tests/evm/test_push.py | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index 0a6de00c2..b45125727 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -318,7 +318,7 @@ def stack_push(self) -> int: def stack_lookup(self, rw: RW, stack_pointer_offset: int) -> int: stack_pointer = self.curr.stack_pointer + stack_pointer_offset - return self.rw_lookup(rw, RWTableTag.Stack, [self.curr.call_id, stack_pointer])[5] + return self.rw_lookup(rw, RWTableTag.Stack, [self.curr.call_id, stack_pointer])[-4] def account_write( self, diff --git a/tests/evm/test_add.py b/tests/evm/test_add.py index 558a33467..40ab84e06 100644 --- a/tests/evm/test_add.py +++ b/tests/evm/test_add.py @@ -45,9 +45,9 @@ def test_add(opcode: Opcode, a_bytes: bytes, b_bytes: bytes, c_bytes: Optional[b bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Read, RWTableTag.Stack, 1, 1022, a, 0, 0, 0, 0), - (10, RW.Read, RWTableTag.Stack, 1, 1023, b, 0, 0, 0, 0), - (11, RW.Write, RWTableTag.Stack, 1, 1023, c, 0, 0, 0, 0), + (9, RW.Read, RWTableTag.Stack, 1, 1022, 0, a, 0, 0, 0), + (10, RW.Read, RWTableTag.Stack, 1, 1023, 0, b, 0, 0, 0), + (11, RW.Write, RWTableTag.Stack, 1, 1023, 0, c, 0, 0, 0), ] ), ) diff --git a/tests/evm/test_coinbase.py b/tests/evm/test_coinbase.py index b5d5ec771..fa65aa5cd 100644 --- a/tests/evm/test_coinbase.py +++ b/tests/evm/test_coinbase.py @@ -32,7 +32,7 @@ def test_coinbase(opcode: Opcode, address: U160): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Write, RWTableTag.Stack, 1, 1023, coinbase_rlc, 0, 0, 0, 0), + (9, RW.Write, RWTableTag.Stack, 1, 1023, 0, coinbase_rlc, 0, 0, 0), ] ), ) diff --git a/tests/evm/test_jump.py b/tests/evm/test_jump.py index e8fc0fed5..8b817d11c 100644 --- a/tests/evm/test_jump.py +++ b/tests/evm/test_jump.py @@ -35,7 +35,7 @@ def test_jump(opcode: Opcode, dest_bytes: bytes): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Read, RWTableTag.Stack, 1, 1021, dest, 0, 0, 0, 0), + (9, RW.Read, RWTableTag.Stack, 1, 1021, 0, dest, 0, 0, 0), ] ), ) diff --git a/tests/evm/test_jumpi.py b/tests/evm/test_jumpi.py index 0b59d8c95..be45890bd 100644 --- a/tests/evm/test_jumpi.py +++ b/tests/evm/test_jumpi.py @@ -36,8 +36,8 @@ def test_jumpi_cond_nonzero(opcode: Opcode, cond_bytes: bytes, dest_bytes: bytes bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Read, RWTableTag.Stack, 1, 1021, dest, 0, 0), - (10, RW.Read, RWTableTag.Stack, 1, 1022, cond, 0, 0), + (9, RW.Read, RWTableTag.Stack, 1, 1021, 0, dest, 0, 0, 0), + (10, RW.Read, RWTableTag.Stack, 1, 1022, 0, cond, 0, 0, 0), ], ), ) @@ -93,8 +93,8 @@ def test_jumpi_cond_zero(opcode: Opcode, cond_bytes: bytes, dest_bytes: bytes): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Read, RWTableTag.Stack, 1, 1021, dest, 0, 0, 0, 0), - (10, RW.Read, RWTableTag.Stack, 1, 1022, cond, 0, 0, 0, 0), + (9, RW.Read, RWTableTag.Stack, 1, 1021, 0, dest, 0, 0, 0), + (10, RW.Read, RWTableTag.Stack, 1, 1022, 0, cond, 0, 0, 0), ], ), ) diff --git a/tests/evm/test_push.py b/tests/evm/test_push.py index dc171bd39..e8b56a49b 100644 --- a/tests/evm/test_push.py +++ b/tests/evm/test_push.py @@ -41,7 +41,7 @@ def test_push(opcode: Opcode, value_be_bytes: bytes): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (8, RW.Write, RWTableTag.Stack, 1, 1023, value, 0, 0, 0, 0), + (8, RW.Write, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), ] ), ) From fc3bf7935478ed4749f9573ee7df8cc2bf2c43f6 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 17 Jan 2022 18:12:57 +0800 Subject: [PATCH 08/37] update --- tests/evm/test_caller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/evm/test_caller.py b/tests/evm/test_caller.py index 9668f3af0..83346b86c 100644 --- a/tests/evm/test_caller.py +++ b/tests/evm/test_caller.py @@ -31,8 +31,8 @@ def test_caller(opcode: Opcode, address: U160): bytecode_table=set(bytecode.table_assignments(rlc_store)), rw_table=set( [ - (9, RW.Write, RWTableTag.Stack, 1, 1023, caller_rlc, 0, 0), - (10, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallerAddress, address, 0, 0), + (9, RW.Write, RWTableTag.Stack, 1, 1023, 0, caller_rlc, 0, 0, 0), + (10, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallerAddress, 0, address, 0, 0, 0), ] ), ) From a4b426736d305fa7c3cccbe744dbe0bf75c92496 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Thu, 20 Jan 2022 11:17:48 +0800 Subject: [PATCH 09/37] fix --- src/zkevm_specs/evm/instruction.py | 4 ++-- tests/evm/test_end_block.py | 2 +- tests/evm/test_end_tx.py | 10 +++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index dd217cb9e..d9a570682 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -516,7 +516,7 @@ def add_account_to_access_list( row = self.rw_lookup( RW.Write, RWTableTag.TxAccessListAccount, - [tx_id, account_address, 1], + [tx_id, account_address, 0, 1], ) return row[-4] - row[-3] @@ -530,7 +530,7 @@ def add_account_to_access_list_with_reversion( ) -> bool: row = self.state_write_with_reversion( RWTableTag.TxAccessListAccount, - [tx_id, account_address, 1], + [tx_id, account_address, 0, 1], is_persistent, rw_counter_end_of_reversion, state_write_counter, diff --git a/tests/evm/test_end_block.py b/tests/evm/test_end_block.py index 21873f85b..005b1be8f 100644 --- a/tests/evm/test_end_block.py +++ b/tests/evm/test_end_block.py @@ -31,7 +31,7 @@ def test_end_block(is_last_step: bool): chain( # dummy read/write for counting [(i, *7 * [0]) for i in range(22)], - [(22, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, tx.id, 0, 0)] + [(22, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, tx.id, 0, 0, 0)] if is_last_step else [], ) diff --git a/tests/evm/test_end_tx.py b/tests/evm/test_end_tx.py index b69725937..284ce88f3 100644 --- a/tests/evm/test_end_tx.py +++ b/tests/evm/test_end_tx.py @@ -58,17 +58,19 @@ def test_end_tx(tx: Transaction, gas_left: int, refund: int, is_last_tx: bool): bytecode_table=set(), rw_table=set( [ - (17, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, tx.id, 0, 0), - (18, RW.Read, RWTableTag.TxRefund, tx.id, refund, refund, 0, 0), + (17, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, tx.id, 0, 0, 0), + (18, RW.Read, RWTableTag.TxRefund, tx.id, 0, 0, refund, refund, 0, 0), ( 19, RW.Write, RWTableTag.Account, tx.caller_address, AccountFieldTag.Balance, + 0, RLC(caller_balance, randomness), RLC(caller_balance_prev, randomness), 0, + 0, ), ( 20, @@ -76,15 +78,17 @@ def test_end_tx(tx: Transaction, gas_left: int, refund: int, is_last_tx: bool): RWTableTag.Account, block.coinbase, AccountFieldTag.Balance, + 0, RLC(coinbase_balance, randomness), RLC(coinbase_balance_prev, randomness), 0, + 0, ), ] + ( [] if is_last_tx - else [(21, RW.Read, RWTableTag.CallContext, 22, CallContextFieldTag.TxId, tx.id + 1, 0, 0)] + else [(21, RW.Read, RWTableTag.CallContext, 22, CallContextFieldTag.TxId, 0, tx.id + 1, 0, 0, 0)] ) ), ) From 47b195badf9981a4ed1625da7a086e65ac69b9ce Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 24 Jan 2022 12:16:38 +0800 Subject: [PATCH 10/37] fix --- tests/evm/test_calldatasize.py | 4 ++-- tests/evm/test_caller.py | 2 +- tests/evm/test_callvalue.py | 4 ++-- tests/evm/test_slt_sgt.py | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/evm/test_calldatasize.py b/tests/evm/test_calldatasize.py index 84bbeecac..0f652fee3 100644 --- a/tests/evm/test_calldatasize.py +++ b/tests/evm/test_calldatasize.py @@ -35,8 +35,8 @@ def test_calldatasize(calldatasize: U64): bytecode_table=set(bytecode.table_assignments(randomness)), rw_table=set( [ - (9, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallDataLength, calldatasize, 0, 0), - (10, RW.Write, RWTableTag.Stack, 1, 1023, RLC(calldatasize, randomness, N_BYTES_U64), 0, 0), + (9, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallDataLength, 0, calldatasize, 0, 0, 0), + (10, RW.Write, RWTableTag.Stack, 1, 1023, 0, RLC(calldatasize, randomness, N_BYTES_U64), 0, 0, 0), ] ), ) diff --git a/tests/evm/test_caller.py b/tests/evm/test_caller.py index c2c802e8c..b04988eac 100644 --- a/tests/evm/test_caller.py +++ b/tests/evm/test_caller.py @@ -37,7 +37,7 @@ def test_caller(caller: U160): rw_table=set( [ (9, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.CallerAddress, 0, caller, 0, 0, 0), - (10, RW.Write, RWTableTag.Stack, 1, 1023, 0, RLC(caller, randomness, N_BYTES_ACCOUNT_ADDRESS), 0, 0, 0), + (10, RW.Write, RWTableTag.Stack, 1, 1023, 0, RLC(caller, randomness, N_BYTES_ACCOUNT_ADDRESS), 0, 0, 0), ] ), ) diff --git a/tests/evm/test_callvalue.py b/tests/evm/test_callvalue.py index 5e4b619bc..48cf38ba1 100644 --- a/tests/evm/test_callvalue.py +++ b/tests/evm/test_callvalue.py @@ -38,8 +38,8 @@ def test_callvalue(callvalue: U256): bytecode_table=set(bytecode.table_assignments(randomness)), rw_table=set( [ - (9, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.Value, callvalue_rlc, 0, 0), - (10, RW.Write, RWTableTag.Stack, 1, 1023, callvalue_rlc, 0, 0), + (9, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.Value, 0, callvalue_rlc, 0, 0, 0), + (10, RW.Write, RWTableTag.Stack, 1, 1023, 0, callvalue_rlc, 0, 0, 0), ] ), ) diff --git a/tests/evm/test_slt_sgt.py b/tests/evm/test_slt_sgt.py index 7d26ccb5c..f0fcb015d 100644 --- a/tests/evm/test_slt_sgt.py +++ b/tests/evm/test_slt_sgt.py @@ -201,9 +201,9 @@ def test_slt_sgt(opcode: Opcode, a: int, b: int, res: int): bytecode_table=set(bytecode.table_assignments(randomness)), rw_table=set( [ - (9, RW.Read, RWTableTag.Stack, 1, 1022, a, 0, 0), - (10, RW.Read, RWTableTag.Stack, 1, 1023, b, 0, 0), - (11, RW.Write, RWTableTag.Stack, 1, 1023, res, 0, 0), + (9, RW.Read, RWTableTag.Stack, 1, 1022, 0, a, 0, 0, 0), + (10, RW.Read, RWTableTag.Stack, 1, 1023, 0, b, 0, 0, 0), + (11, RW.Write, RWTableTag.Stack, 1, 1023, 0, res, 0, 0, 0), ] ), ) From 1b0a6f1062306991755a65faade4fd60d1e11be4 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 24 Jan 2022 17:19:01 +0800 Subject: [PATCH 11/37] update --- specs/opcode/54SLOAD_55SSTORE.md | 91 ++++++++ src/zkevm_specs/evm/execution/__init__.py | 2 + src/zkevm_specs/evm/execution/gas.py | 6 + src/zkevm_specs/evm/execution/storage.py | 107 +++++++++ tests/evm/test_sload.py | 171 ++++++++++++++ tests/evm/test_sstore.py | 269 ++++++++++++++++++++++ 6 files changed, 646 insertions(+) create mode 100644 specs/opcode/54SLOAD_55SSTORE.md create mode 100644 src/zkevm_specs/evm/execution/gas.py create mode 100644 src/zkevm_specs/evm/execution/storage.py create mode 100644 tests/evm/test_sload.py create mode 100644 tests/evm/test_sstore.py diff --git a/specs/opcode/54SLOAD_55SSTORE.md b/specs/opcode/54SLOAD_55SSTORE.md new file mode 100644 index 000000000..c498fa63c --- /dev/null +++ b/specs/opcode/54SLOAD_55SSTORE.md @@ -0,0 +1,91 @@ +# SLOAD & SSTORE op code + +## Variables definition + +| Name | Value | +| - | - | +| COLD_SLOAD_COST | 2100 | +| WARM_STORAGE_READ_COST | 100 | +| SLOAD_GAS | 100 | +| SSTORE_SET_GAS | 20000 | +| SSTORE_RESET_GAS | 2900 | +| SSTORE_CLEARS_SCHEDULE | 15000 | + +## Constraints + +1. opcodeId checks + 1. opId === OpcodeId(0x54) for `SLOAD` + 2. opId === OpcodeId(0x55) for `SSTORE` +2. state transition: + - gc + - `SLOAD`: +5 (2 stack operations + 1 storage reads + 2 access_list reads/writes) + - `SSTORE`: +8 + + 2 stack operations + + 2 storage reads/writes + + 2 access_list reads/writes + + 2 gas_refund reads/writes + - stack_pointer + - `SLOAD`: remains the same + - `SSTORE`: -2 + - pc + 1 + - state_write_counter + - `SLOAD`: +1 (access_list) + - `SSTORE`: +3 (for storage, access_list & gas_refund respectively) + - gas: + - `SLOAD`: + + the accessed address is warm: gas + WARM_STORAGE_READ_COST + + the accessed address is cold: gas + COLD_SLOAD_COST + - `SSTORE`: + + the accessed address is warm: + * `current_value == new_value`: gas + SLOAD_GAS + * `current_value != new_value`: + - `original_value == current_value`: + - `original_value == 0`: gas + SSTORE_SET_GAS + - `original_value != 0`: gas + SSTORE_RESET_GAS + - `original_value != current_value`: gas + SLOAD_GAS + + the accessed address is cold: + * `current_value == new_value`: gas + SLOAD_GAS + COLD_SLOAD_COST + * `current_value != new_value`: + - `original_value == current_value`: + - `original_value == 0`: gas + SSTORE_SET_GAS + COLD_SLOAD_COST + - `original_value != 0`: gas + SSTORE_RESET_GAS + COLD_SLOAD_COST + - `original_value != current_value`: gas + SLOAD_GAS + COLD_SLOAD_COST + * gas_refund: + - `SSTORE`: + + `current_value != new_value`: + * `original_value == current_value`: + * `original_value != 0` && `new_value == 0`: gas_refund + SSTORE_CLEARS_SCHEDULE + * `original_value != current_value`: + * `original_value != 0`: + - `current_value == 0`: gas_refund - SSTORE_CLEARS_SCHEDULE + - `new_value == 0`: gas_refund + SSTORE_CLEARS_SCHEDULE + * `original_value == new_value`: + - `original_value == 0`: gas_refund + SSTORE_SET_GAS - SLOAD_GAS + - `original_value != 0`: gas_refund + SSTORE_RESET_GAS - SLOAD_GAS +3. lookups: + - `SLOAD`: 5 busmapping lookups + - stack: + - `address` is popped off the top of the stack + - `value` is pushed on top of the stack + - storage: The 32 bytes of `value` are read from storage at `address` + - access_list: Whether the address is warm (accessed before), mark as warm afterward + - `SSTORE`: 8 busmapping lookups + - stack: + - `address` is popped off the top of the stack + - `value` is popped off the top of the stack + - storage: + - Read the orignal_value and the current_value at `address` + - The 32 bytes of new `value` are written to storage at `address` + - access_list: Whether the address is warm (accessed before), mark as warm afterward + - gas_refund: + + Read the accumulated gas_refund for this tx + + Write the new accumulated gas_refund for this tx + +## Exceptions + +1. gas out: remaining gas is not enough +2. stack underflow: + - the stack is empty: `1024 == stack_pointer` + - only for `SSTORE`: contains a single value: `1023 == stack_pointer` +3. context error + - only for `SSTORE`: the current execution context is from a `STATICCALL` (since Byzantium fork). diff --git a/src/zkevm_specs/evm/execution/__init__.py b/src/zkevm_specs/evm/execution/__init__.py index 9a8e3deab..6c4eecdfa 100644 --- a/src/zkevm_specs/evm/execution/__init__.py +++ b/src/zkevm_specs/evm/execution/__init__.py @@ -16,6 +16,8 @@ from .slt_sgt import * from .callvalue import * from .calldatasize import * +from .gas import * +from .storage import * EXECUTION_STATE_IMPL: Dict[ExecutionState, Callable] = { diff --git a/src/zkevm_specs/evm/execution/gas.py b/src/zkevm_specs/evm/execution/gas.py new file mode 100644 index 000000000..6904f7db3 --- /dev/null +++ b/src/zkevm_specs/evm/execution/gas.py @@ -0,0 +1,6 @@ +COLD_SLOAD_COST = 2100 +WARM_STORAGE_READ_COST = 100 +SLOAD_GAS = 100 +SSTORE_SET_GAS = 20000 +SSTORE_RESET_GAS = 2900 +SSTORE_CLEARS_SCHEDULE = 15000 diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py new file mode 100644 index 000000000..0573ffbb8 --- /dev/null +++ b/src/zkevm_specs/evm/execution/storage.py @@ -0,0 +1,107 @@ +from ..instruction import Instruction, Transition +from ..opcode import Opcode +from ..table import CallContextFieldTag, TxContextFieldTag +from .gas import ( + COLD_SLOAD_COST, + WARM_STORAGE_READ_COST, + SLOAD_GAS, + SSTORE_SET_GAS, + SSTORE_RESET_GAS, + SSTORE_CLEARS_SCHEDULE, +) + + +def sload(instruction: Instruction): + opcode = instruction.opcode_lookup(True) + instruction.constrain_equal(opcode, Opcode.SLOAD) + + 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) + callee_address = instruction.tx_lookup(tx_id, TxContextFieldTag.CalleeAddress) + + storage_slot = instruction.stack_pop() + warm, _ = instruction.access_list_storage_slot_read(tx_id, callee_address, storage_slot) + + # TODO: Use intrinsic gas (EIP 2028, 2930) + dynamic_gas_cost = WARM_STORAGE_READ_COST if warm else COLD_SLOAD_COST + + instruction.storage_slot_read(callee_address, storage_slot) + instruction.add_storage_slot_to_access_list_with_reversion( + tx_id, callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + ) + instruction.stack_push() + + instruction.constrain_same_context_state_transition( + opcode, + rw_counter=Transition.delta(5), + program_counter=Transition.delta(1), + stack_pointer=Transition.delta(0), + state_write_counter=Transition.delta(1), + dynamic_gas_cost=dynamic_gas_cost, + ) + + +def sstore(instruction: Instruction): + opcode = instruction.opcode_lookup(True) + instruction.constrain_equal(opcode, Opcode.SSTORE) + + 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) + callee_address = instruction.tx_lookup(tx_id, TxContextFieldTag.CalleeAddress) + + storage_slot = instruction.stack_pop() + new_value = instruction.stack_pop() + warm, _ = instruction.access_list_storage_slot_read(tx_id, callee_address, storage_slot) + current_value, _, txid, original_value = instruction.storage_slot_read(callee_address, storage_slot) + instruction.constrain_equal(tx_id, txid) + + # TODO: Use intrinsic gas (EIP 2028, 2930) + if current_value == new_value: + dynamic_gas_cost = SLOAD_GAS + else: + if original_value == current_value: + if original_value == 0: + dynamic_gas_cost = SSTORE_SET_GAS + else: + dynamic_gas_cost = SSTORE_RESET_GAS + else: + dynamic_gas_cost = SLOAD_GAS + if not warm: + dynamic_gas_cost = dynamic_gas_cost + COLD_SLOAD_COST + + gas_refund, _ = instruction.gas_refund_read(tx_id) + if current_value != new_value: + if original_value == current_value: + if original_value != 0 and new_value == 0: + gas_refund = gas_refund + SSTORE_CLEARS_SCHEDULE + else: + if original_value != 0: + if current_value == 0: + gas_refund = gas_refund - SSTORE_CLEARS_SCHEDULE + if new_value == 0: + gas_refund = gas_refund + SSTORE_CLEARS_SCHEDULE + if original_value == new_value: + if original_value == 0: + gas_refund = gas_refund + SSTORE_SET_GAS - SLOAD_GAS + else: + gas_refund = gas_refund + SSTORE_RESET_GAS - SLOAD_GAS + + instruction.storage_slot_write_with_reversion( + callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + ) + instruction.add_storage_slot_to_access_list_with_reversion( + tx_id, callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + ) + new_gas_refund, _ = instruction.gas_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) + instruction.constrain_equal(gas_refund, new_gas_refund) + + instruction.constrain_same_context_state_transition( + opcode, + rw_counter=Transition.delta(8), + program_counter=Transition.delta(1), + stack_pointer=Transition.delta(2), + state_write_counter=Transition.delta(3), + dynamic_gas_cost=dynamic_gas_cost, + ) diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py new file mode 100644 index 000000000..ab55cfd4e --- /dev/null +++ b/tests/evm/test_sload.py @@ -0,0 +1,171 @@ +import pytest + +from zkevm_specs.evm import ( + ExecutionState, + StepState, + verify_steps, + Tables, + RWTableTag, + RW, + CallContextFieldTag, + Transaction, + Block, + Bytecode, +) +from zkevm_specs.evm.execution.params import COLD_SLOAD_COST, WARM_STORAGE_READ_COST +from zkevm_specs.util import rand_fp, rand_address, RLC + +TESTING_DATA = ( + ( + Transaction(caller_address=rand_address(), callee_address=rand_address()), + bytes([i for i in range(32, 0, -1)]), + False, + True, + ), + ( + Transaction(caller_address=rand_address(), callee_address=rand_address()), + bytes([i for i in range(32, 0, -1)]), + True, + True, + ), + ( + Transaction(caller_address=rand_address(), callee_address=rand_address()), + bytes([i for i in range(32, 0, -1)]), + False, + False, + ), + ( + Transaction(caller_address=rand_address(), callee_address=rand_address()), + bytes([i for i in range(32, 0, -1)]), + True, + False, + ), +) + + +@pytest.mark.parametrize("tx, slot_be_bytes, warm, result", TESTING_DATA) +def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): + randomness = rand_fp() + + storage_slot = RLC(bytes(reversed(slot_be_bytes)), randomness) + + block = Block() + + # PUSH32 STORAGE_SLOT SLOAD STOP + bytecode = Bytecode(f"7f{slot_be_bytes.hex()}5400") + bytecode_hash = RLC(bytecode.hash(), randomness) + + value = 2 + value_prev = 0 + value_committed = 0 + + tables = Tables( + block_table=set(block.table_assignments(rlc_store)), + tx_table=set(tx.table_assignments(rlc_store)), + bytecode_table=set(bytecode.table_assignments(rlc_store)), + rw_table=set( + [ + (9, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, tx.id, 0, 0, 0), + ( + 10, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.RWCounterEndOfReversion, + 0, + 0 if result else 19, + 0, + 0, + 0, + ), + (11, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), + (12, RW.Read, RWTableTag.Stack, 1, 1023, 0, storage_slot, 0, 0, 0), + ( + 13, + RW.Read, + RWTableTag.TxAccessListStorageSlot, + tx.id, + tx.callee_address, + storage_slot, + 1 if warm else 0, + 0, + 0, + 0, + ), + ( + 14, + RW.Read, + RWTableTag.AccountStorage, + tx.callee_address, + storage_slot, + 0, + value, + value_prev, + tx.id, + value_committed, + ), + ( + 15, + RW.Write, + RWTableTag.TxAccessListStorageSlot, + tx.id, + tx.callee_address, + storage_slot, + 1, + 1 if warm else 0, + 0, + 0, + ), + (16, RW.Write, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), + ] + + ( + [] + if result + else [ + ( + 19, + RW.Write, + RWTableTag.TxAccessListStorageSlot, + tx.id, + tx.callee_address, + storage_slot, + 1 if warm else 0, + 1, + 0, + 0, + ), + ] + ) + ), + ) + + verify_steps( + rlc_store=rlc_store, + tables=tables, + steps=[ + StepState( + execution_state=ExecutionState.SLOAD, + rw_counter=9, + call_id=1, + is_root=True, + is_create=False, + opcode_source=bytecode_hash, + program_counter=33, + stack_pointer=1023, + state_write_counter=0, + gas_left=WARM_STORAGE_READ_COST if warm else COLD_SLOAD_COST, + ), + StepState( + execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, + rw_counter=14, + call_id=1, + is_root=True, + is_create=False, + opcode_source=bytecode_hash, + program_counter=34, + stack_pointer=1023, + state_write_counter=1, + gas_left=0, + ), + ], + ) diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py new file mode 100644 index 000000000..a7ccec3a4 --- /dev/null +++ b/tests/evm/test_sstore.py @@ -0,0 +1,269 @@ +import pytest + +from zkevm_specs.evm import ( + ExecutionState, + StepState, + verify_steps, + Tables, + RWTableTag, + RW, + CallContextFieldTag, + Transaction, + Block, + Bytecode, +) +from zkevm_specs.evm.execution.params import ( + COLD_SLOAD_COST, + WARM_STORAGE_READ_COST, + SLOAD_GAS, + SSTORE_SET_GAS, + SSTORE_RESET_GAS, + SSTORE_CLEARS_SCHEDULE, +) +from zkevm_specs.util import rand_fp, rand_address, RLC + + +def gen_test_cases(): + value_cases = [ + [bytes([i for i in range(0, 32, 1)]), 0, -1], # value_prev == value + # "value_prev != value, original_value == value_prev, original_value == 0" case is skipped because inconvenient to generate for now + [ + bytes([i for i in range(0, 32, 1)]), + -1, + -1, + ], # value_prev != value, original_value == value_prev, original_value != 0 + [bytes([i for i in range(0, 32, 1)]), -1, -2], # value_prev != value, original_value != value_prev + [ + bytes([i for i in range(0, 32, 1)]), + -1, + 0, + ], # value_prev != value, original_value != value_prev, value == original_value + ] + warm_cases = [False, True] + persist_cases = [True, False] + + test_cases = [] + for value_case in value_cases: + for warm_case in warm_cases: + for persist_case in persist_cases: + test_cases.append( + ( + Transaction(caller_address=rand_address(), callee_address=rand_address()), # tx + bytes([i for i in range(32, 0, -1)]), # storage_slot + value_case[0], # new_value + value_case[1], # value_prev_diff + value_case[2], # original_value_diff + warm_case, # is_warm_storage_slot + persist_case, # is_not_reverted + ) + ) + return test_cases + + +TESTING_DATA = gen_test_cases() + + +@pytest.mark.parametrize( + "tx, slot_be_bytes, value_be_bytes, value_prev_diff, original_value_diff, warm, result", TESTING_DATA +) +def test_sstore( + tx: Transaction, + slot_be_bytes: bytes, + value_be_bytes: bytes, + value_prev_diff: int, + original_value_diff: int, + warm: bool, + result: bool, +): + randomness = rand_fp() + + storage_slot = RLC(bytes(reversed(slot_be_bytes)), randomness) + value = RLC(bytes(reversed(value_be_bytes)), randomness) + value_prev = value + value_prev_diff + original_value = value + original_value_diff + + block = Block() + + # PUSH32 STORAGE_SLOT PUSH32 VALUE SSTORE STOP + bytecode = Bytecode(f"7f{slot_be_bytes.hex()}7f{value_be_bytes.hex()}5500") + bytecode_hash = RLC(bytecode.hash(), randomness) + + if value_prev == value: + expected_gas_cost = SLOAD_GAS + else: + if original_value == value_prev: + if original_value == 0: + expected_gas_cost = SSTORE_SET_GAS + else: + expected_gas_cost = SSTORE_RESET_GAS + else: + expected_gas_cost = SLOAD_GAS + if not warm: + expected_gas_cost = expected_gas_cost + COLD_SLOAD_COST + + old_gas_refund = 15000 + gas_refund = old_gas_refund + if value_prev != value: + if original_value == value_prev: + if original_value != 0 and value == 0: + gas_refund = gas_refund + SSTORE_CLEARS_SCHEDULE + else: + if original_value != 0: + if value_prev == 0: + gas_refund = gas_refund - SSTORE_CLEARS_SCHEDULE + if value == 0: + gas_refund = gas_refund + SSTORE_CLEARS_SCHEDULE + if original_value == value: + if original_value == 0: + gas_refund = gas_refund + SSTORE_SET_GAS - SLOAD_GAS + else: + gas_refund = gas_refund + SSTORE_RESET_GAS - SLOAD_GAS + + tables = Tables( + block_table=set(block.table_assignments(rlc_store)), + tx_table=set(tx.table_assignments(rlc_store)), + bytecode_table=set(bytecode.table_assignments(rlc_store)), + rw_table=set( + [ + (1, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, tx.id, 0, 0, 0), + ( + 2, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.RWCounterEndOfReversion, + 0, + 0 if result else 16, + 0, + 0, + 0, + ), + (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), + (4, RW.Read, RWTableTag.Stack, 1, 1022, 0, storage_slot, 0, 0, 0), + (5, RW.Read, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), + ( + 6, + RW.Read, + RWTableTag.TxAccessListStorageSlot, + tx.id, + tx.callee_address, + storage_slot, + 1 if warm else 0, + 0, + 0, + 0, + ), + ( + 7, + RW.Read, + RWTableTag.AccountStorage, + tx.callee_address, + storage_slot, + 0, + value_prev, + original_value, + tx.id, + original_value, + ), + (8, RW.Read, RWTableTag.TxRefund, tx.id, 0, 0, old_gas_refund, 0, 0, 0), + ( + 9, + RW.Write, + RWTableTag.AccountStorage, + tx.callee_address, + storage_slot, + 0, + value, + value_prev, + tx.id, + original_value, + ), + ( + 10, + RW.Write, + RWTableTag.TxAccessListStorageSlot, + tx.id, + tx.callee_address, + storage_slot, + 1, + 1 if warm else 0, + 0, + 0, + ), + (11, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), + ] + + ( + [] + if result + else [ + ( + 14, + RW.Write, + RWTableTag.TxRefund, + tx.id, + 0, + 0, + old_gas_refund, + gas_refund, + 0, + 0, + ), + ( + 15, + RW.Write, + RWTableTag.TxAccessListStorageSlot, + tx.id, + tx.callee_address, + storage_slot, + 1 if warm else 0, + 1, + 0, + 0, + ), + ( + 16, + RW.Write, + RWTableTag.AccountStorage, + tx.callee_address, + storage_slot, + 0, + value_prev, + value, + tx.id, + original_value, + ), + ] + ) + ), + ) + + verify_steps( + rlc_store=rlc_store, + tables=tables, + steps=[ + StepState( + execution_state=ExecutionState.SSTORE, + rw_counter=1, + call_id=1, + is_root=True, + is_create=False, + opcode_source=bytecode_hash, + program_counter=66, + stack_pointer=1022, + state_write_counter=0, + gas_left=expected_gas_cost, + ), + StepState( + execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, + rw_counter=9, + call_id=1, + is_root=True, + is_create=False, + opcode_source=bytecode_hash, + program_counter=67, + stack_pointer=1024, + state_write_counter=3, + gas_left=0, + ), + ], + ) From cbf96cb063a1d62f84f29e3972e9a3d3d34d8f39 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 24 Jan 2022 17:29:52 +0800 Subject: [PATCH 12/37] fix test_sload --- src/zkevm_specs/evm/execution/__init__.py | 2 ++ src/zkevm_specs/evm/execution/storage.py | 30 +++++++++++------------ src/zkevm_specs/evm/instruction.py | 17 +++++++++++++ tests/evm/test_sload.py | 24 +++++++++--------- tests/evm/test_sstore.py | 14 +++++------ 5 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/zkevm_specs/evm/execution/__init__.py b/src/zkevm_specs/evm/execution/__init__.py index 6c4eecdfa..f6fe4958f 100644 --- a/src/zkevm_specs/evm/execution/__init__.py +++ b/src/zkevm_specs/evm/execution/__init__.py @@ -33,4 +33,6 @@ ExecutionState.JUMPI: jumpi, ExecutionState.PUSH: push, ExecutionState.SCMP: scmp, + ExecutionState.SLOAD: sload, + ExecutionState.SSTORE: sstore, } diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 0573ffbb8..deeb9204f 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -16,23 +16,23 @@ def sload(instruction: Instruction): instruction.constrain_equal(opcode, Opcode.SLOAD) tx_id = instruction.call_context_lookup(CallContextFieldTag.TxId) - rw_counter_end_of_reversion = instruction.call_context_lookup(CallContextFieldTag.RWCounterEndOfReversion) + rw_counter_end_of_reversion = instruction.call_context_lookup(CallContextFieldTag.RwCounterEndOfReversion) is_persistent = instruction.call_context_lookup(CallContextFieldTag.IsPersistent) - callee_address = instruction.tx_lookup(tx_id, TxContextFieldTag.CalleeAddress) + tx_callee_address = instruction.tx_context_lookup(tx_id, TxContextFieldTag.CalleeAddress) storage_slot = instruction.stack_pop() - warm, _ = instruction.access_list_storage_slot_read(tx_id, callee_address, storage_slot) + warm, _ = instruction.access_list_account_storage_read(tx_id, tx_callee_address, storage_slot) # TODO: Use intrinsic gas (EIP 2028, 2930) dynamic_gas_cost = WARM_STORAGE_READ_COST if warm else COLD_SLOAD_COST - instruction.storage_slot_read(callee_address, storage_slot) - instruction.add_storage_slot_to_access_list_with_reversion( - tx_id, callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + instruction.account_storage_read(tx_callee_address, storage_slot) + instruction.add_account_storage_to_access_list_with_reversion( + tx_id, tx_callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion ) instruction.stack_push() - instruction.constrain_same_context_state_transition( + instruction.step_state_transition_in_same_context( opcode, rw_counter=Transition.delta(5), program_counter=Transition.delta(1), @@ -47,14 +47,14 @@ def sstore(instruction: Instruction): instruction.constrain_equal(opcode, Opcode.SSTORE) tx_id = instruction.call_context_lookup(CallContextFieldTag.TxId) - rw_counter_end_of_reversion = instruction.call_context_lookup(CallContextFieldTag.RWCounterEndOfReversion) + rw_counter_end_of_reversion = instruction.call_context_lookup(CallContextFieldTag.RwCounterEndOfReversion) is_persistent = instruction.call_context_lookup(CallContextFieldTag.IsPersistent) - callee_address = instruction.tx_lookup(tx_id, TxContextFieldTag.CalleeAddress) + tx_callee_address = instruction.tx_context_lookup(tx_id, TxContextFieldTag.CalleeAddress) storage_slot = instruction.stack_pop() new_value = instruction.stack_pop() - warm, _ = instruction.access_list_storage_slot_read(tx_id, callee_address, storage_slot) - current_value, _, txid, original_value = instruction.storage_slot_read(callee_address, storage_slot) + warm, _ = instruction.access_list_account_storage_read(tx_id, tx_callee_address, storage_slot) + current_value, _, txid, original_value = instruction.account_storage_read(tx_callee_address, storage_slot) instruction.constrain_equal(tx_id, txid) # TODO: Use intrinsic gas (EIP 2028, 2930) @@ -89,15 +89,15 @@ def sstore(instruction: Instruction): gas_refund = gas_refund + SSTORE_RESET_GAS - SLOAD_GAS instruction.storage_slot_write_with_reversion( - callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + tx_callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion ) - instruction.add_storage_slot_to_access_list_with_reversion( - tx_id, callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + instruction.add_account_storage_to_access_list_with_reversion( + tx_id, tx_callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion ) new_gas_refund, _ = instruction.gas_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) instruction.constrain_equal(gas_refund, new_gas_refund) - instruction.constrain_same_context_state_transition( + instruction.step_state_transition_in_same_context( opcode, rw_counter=Transition.delta(8), program_counter=Transition.delta(1), diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index d9a570682..9d10dceff 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -508,6 +508,10 @@ def sub_balance_with_reversion( self.constrain_zero(carry) return balance, balance_prev + def account_storage_read(self, account_address: int, storage_key: int) -> Tuple[int, int]: + row = self.rw_lookup(RW.Read, RWTableTag.AccountStorage, [account_address, storage_key, 0]) + return row[-4], row[-3] + def add_account_to_access_list( self, tx_id: int, @@ -537,6 +541,19 @@ def add_account_to_access_list_with_reversion( ) return row[-4] - row[-3] + def access_list_account_storage_read( + self, + tx_id: int, + account_address: int, + storage_key: int, + ) -> Tuple[int, int]: + row = self.rw_lookup( + RW.Read, + RWTableTag.TxAccessListAccountStorage, + [tx_id, account_address, storage_key], + ) + return row[-4], row[-3] + def add_account_storage_to_access_list( self, tx_id: int, diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index ab55cfd4e..2bd0535a4 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -49,10 +49,8 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): storage_slot = RLC(bytes(reversed(slot_be_bytes)), randomness) - block = Block() - # PUSH32 STORAGE_SLOT SLOAD STOP - bytecode = Bytecode(f"7f{slot_be_bytes.hex()}5400") + bytecode = Bytecode().push32(slot_be_bytes).sload().stop() bytecode_hash = RLC(bytecode.hash(), randomness) value = 2 @@ -60,9 +58,9 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): value_committed = 0 tables = Tables( - block_table=set(block.table_assignments(rlc_store)), - tx_table=set(tx.table_assignments(rlc_store)), - bytecode_table=set(bytecode.table_assignments(rlc_store)), + block_table=set(Block().table_assignments(randomness)), + tx_table=set(tx.table_assignments(randomness)), + bytecode_table=set(bytecode.table_assignments(randomness)), rw_table=set( [ (9, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, tx.id, 0, 0, 0), @@ -71,7 +69,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): RW.Read, RWTableTag.CallContext, 1, - CallContextFieldTag.RWCounterEndOfReversion, + CallContextFieldTag.RwCounterEndOfReversion, 0, 0 if result else 19, 0, @@ -83,7 +81,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): ( 13, RW.Read, - RWTableTag.TxAccessListStorageSlot, + RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, storage_slot, @@ -107,7 +105,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): ( 15, RW.Write, - RWTableTag.TxAccessListStorageSlot, + RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, storage_slot, @@ -125,7 +123,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): ( 19, RW.Write, - RWTableTag.TxAccessListStorageSlot, + RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, storage_slot, @@ -140,7 +138,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): ) verify_steps( - rlc_store=rlc_store, + randomness=randomness, tables=tables, steps=[ StepState( @@ -149,7 +147,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): call_id=1, is_root=True, is_create=False, - opcode_source=bytecode_hash, + code_source=bytecode_hash, program_counter=33, stack_pointer=1023, state_write_counter=0, @@ -161,7 +159,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): call_id=1, is_root=True, is_create=False, - opcode_source=bytecode_hash, + code_source=bytecode_hash, program_counter=34, stack_pointer=1023, state_write_counter=1, diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index a7ccec3a4..5c5b13b28 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -131,7 +131,7 @@ def test_sstore( RW.Read, RWTableTag.CallContext, 1, - CallContextFieldTag.RWCounterEndOfReversion, + CallContextFieldTag.RwCounterEndOfReversion, 0, 0 if result else 16, 0, @@ -144,7 +144,7 @@ def test_sstore( ( 6, RW.Read, - RWTableTag.TxAccessListStorageSlot, + RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, storage_slot, @@ -181,7 +181,7 @@ def test_sstore( ( 10, RW.Write, - RWTableTag.TxAccessListStorageSlot, + RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, storage_slot, @@ -211,7 +211,7 @@ def test_sstore( ( 15, RW.Write, - RWTableTag.TxAccessListStorageSlot, + RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, storage_slot, @@ -238,7 +238,7 @@ def test_sstore( ) verify_steps( - rlc_store=rlc_store, + randomness=randomness, tables=tables, steps=[ StepState( @@ -247,7 +247,7 @@ def test_sstore( call_id=1, is_root=True, is_create=False, - opcode_source=bytecode_hash, + code_source=bytecode_hash, program_counter=66, stack_pointer=1022, state_write_counter=0, @@ -259,7 +259,7 @@ def test_sstore( call_id=1, is_root=True, is_create=False, - opcode_source=bytecode_hash, + code_source=bytecode_hash, program_counter=67, stack_pointer=1024, state_write_counter=3, From 77208d09ddc1f26daaff0a16dcbdf94124059016 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Mon, 24 Jan 2022 21:54:56 +0800 Subject: [PATCH 13/37] t# This is a combination of 2 commits. fix test_sstore --- src/zkevm_specs/evm/execution/storage.py | 6 +-- src/zkevm_specs/evm/instruction.py | 35 ++++++++++++++++- tests/evm/test_sload.py | 1 - tests/evm/test_sstore.py | 49 ++++++++++++++---------- 4 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index deeb9204f..4793fc305 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -71,7 +71,7 @@ def sstore(instruction: Instruction): if not warm: dynamic_gas_cost = dynamic_gas_cost + COLD_SLOAD_COST - gas_refund, _ = instruction.gas_refund_read(tx_id) + gas_refund = instruction.tx_refund_read(tx_id) if current_value != new_value: if original_value == current_value: if original_value != 0 and new_value == 0: @@ -88,13 +88,13 @@ def sstore(instruction: Instruction): else: gas_refund = gas_refund + SSTORE_RESET_GAS - SLOAD_GAS - instruction.storage_slot_write_with_reversion( + instruction.account_storage_write_with_reversion( tx_callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion ) instruction.add_account_storage_to_access_list_with_reversion( tx_id, tx_callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion ) - new_gas_refund, _ = instruction.gas_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) + new_gas_refund, _ = instruction.tx_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) instruction.constrain_equal(gas_refund, new_gas_refund) instruction.step_state_transition_in_same_context( diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index 9d10dceff..e4d0fa746 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -429,6 +429,22 @@ def tx_refund_read(self, tx_id) -> int: row = self.rw_lookup(RW.Read, RWTableTag.TxRefund, [tx_id]) return row[-4] + def tx_refund_write_with_reversion( + self, + tx_id: int, + is_persistent: bool, + rw_counter_end_of_reversion: int, + state_write_counter: Optional[int] = None, + ) -> Tuple[int, int]: + row = self.state_write_with_reversion( + RWTableTag.TxRefund, + [tx_id], + is_persistent, + rw_counter_end_of_reversion, + state_write_counter, + ) + return row[-4], row[-3] + def account_read(self, account_address: int, account_field_tag: AccountFieldTag) -> int: row = self.rw_lookup(RW.Read, RWTableTag.Account, [account_address, account_field_tag]) return row[-4] @@ -508,8 +524,25 @@ def sub_balance_with_reversion( self.constrain_zero(carry) return balance, balance_prev - def account_storage_read(self, account_address: int, storage_key: int) -> Tuple[int, int]: + def account_storage_read(self, account_address: int, storage_key: int) -> Tuple[int, int, int, int]: row = self.rw_lookup(RW.Read, RWTableTag.AccountStorage, [account_address, storage_key, 0]) + return row[-4], row[-3], row[-2], row[-1] + + def account_storage_write_with_reversion( + self, + account_address: int, + storage_key: int, + is_persistent: bool, + rw_counter_end_of_reversion: int, + state_write_counter: Optional[int] = None, + ) -> Tuple[int, int]: + row = self.state_write_with_reversion( + RWTableTag.AccountStorage, + [account_address, storage_key], + is_persistent, + rw_counter_end_of_reversion, + state_write_counter, + ) return row[-4], row[-3] def add_account_to_access_list( diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index 2bd0535a4..c14934ad9 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -49,7 +49,6 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): storage_slot = RLC(bytes(reversed(slot_be_bytes)), randomness) - # PUSH32 STORAGE_SLOT SLOAD STOP bytecode = Bytecode().push32(slot_be_bytes).sload().stop() bytecode_hash = RLC(bytecode.hash(), randomness) diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index 5c5b13b28..cf95364af 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -25,18 +25,30 @@ def gen_test_cases(): value_cases = [ - [bytes([i for i in range(0, 32, 1)]), 0, -1], # value_prev == value - # "value_prev != value, original_value == value_prev, original_value == 0" case is skipped because inconvenient to generate for now [ bytes([i for i in range(0, 32, 1)]), - -1, - -1, + bytes([i for i in range(0, 32, 1)]), + bytes([i for i in range(0, 32, 1)]), + ], # value_prev == value + [ + bytes([1]), + bytes([0]), + bytes([0]), + ], # value_prev != value, original_value == value_prev, original_value == 0 + [ + bytes([2]), + bytes([1]), + bytes([1]), ], # value_prev != value, original_value == value_prev, original_value != 0 - [bytes([i for i in range(0, 32, 1)]), -1, -2], # value_prev != value, original_value != value_prev [ - bytes([i for i in range(0, 32, 1)]), - -1, - 0, + bytes([3]), + bytes([2]), + bytes([1]), + ], # value_prev != value, original_value != value_prev + [ + bytes([1]), + bytes([2]), + bytes([1]), ], # value_prev != value, original_value != value_prev, value == original_value ] warm_cases = [False, True] @@ -64,14 +76,14 @@ def gen_test_cases(): @pytest.mark.parametrize( - "tx, slot_be_bytes, value_be_bytes, value_prev_diff, original_value_diff, warm, result", TESTING_DATA + "tx, slot_be_bytes, value_be_bytes, value_prev_be_bytes, original_value_be_bytes, warm, result", TESTING_DATA ) def test_sstore( tx: Transaction, slot_be_bytes: bytes, value_be_bytes: bytes, - value_prev_diff: int, - original_value_diff: int, + value_prev_be_bytes: int, + original_value_be_bytes: int, warm: bool, result: bool, ): @@ -79,13 +91,10 @@ def test_sstore( storage_slot = RLC(bytes(reversed(slot_be_bytes)), randomness) value = RLC(bytes(reversed(value_be_bytes)), randomness) - value_prev = value + value_prev_diff - original_value = value + original_value_diff - - block = Block() + value_prev = RLC(bytes(reversed(value_prev_be_bytes)), randomness) + original_value = RLC(bytes(reversed(original_value_be_bytes)), randomness) - # PUSH32 STORAGE_SLOT PUSH32 VALUE SSTORE STOP - bytecode = Bytecode(f"7f{slot_be_bytes.hex()}7f{value_be_bytes.hex()}5500") + bytecode = Bytecode().push32(slot_be_bytes).push32(value_be_bytes).sstore().stop() bytecode_hash = RLC(bytecode.hash(), randomness) if value_prev == value: @@ -120,9 +129,9 @@ def test_sstore( gas_refund = gas_refund + SSTORE_RESET_GAS - SLOAD_GAS tables = Tables( - block_table=set(block.table_assignments(rlc_store)), - tx_table=set(tx.table_assignments(rlc_store)), - bytecode_table=set(bytecode.table_assignments(rlc_store)), + block_table=set(Block().table_assignments(randomness)), + tx_table=set(tx.table_assignments(randomness)), + bytecode_table=set(bytecode.table_assignments(randomness)), rw_table=set( [ (1, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, tx.id, 0, 0, 0), From 72e099d6e7a0333607aace471e5e0aee1741fba8 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Tue, 25 Jan 2022 10:38:59 +0800 Subject: [PATCH 14/37] rename --- src/zkevm_specs/evm/execution/storage.py | 18 ++++++++-------- tests/evm/test_sload.py | 18 ++++++++-------- tests/evm/test_sstore.py | 26 ++++++++++++------------ 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 4793fc305..d9bcbec43 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -20,15 +20,15 @@ def sload(instruction: Instruction): is_persistent = instruction.call_context_lookup(CallContextFieldTag.IsPersistent) tx_callee_address = instruction.tx_context_lookup(tx_id, TxContextFieldTag.CalleeAddress) - storage_slot = instruction.stack_pop() - warm, _ = instruction.access_list_account_storage_read(tx_id, tx_callee_address, storage_slot) + storage_key = instruction.stack_pop() + warm, _ = instruction.access_list_account_storage_read(tx_id, tx_callee_address, storage_key) # TODO: Use intrinsic gas (EIP 2028, 2930) dynamic_gas_cost = WARM_STORAGE_READ_COST if warm else COLD_SLOAD_COST - instruction.account_storage_read(tx_callee_address, storage_slot) + instruction.account_storage_read(tx_callee_address, storage_key) instruction.add_account_storage_to_access_list_with_reversion( - tx_id, tx_callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + tx_id, tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) instruction.stack_push() @@ -51,10 +51,10 @@ def sstore(instruction: Instruction): is_persistent = instruction.call_context_lookup(CallContextFieldTag.IsPersistent) tx_callee_address = instruction.tx_context_lookup(tx_id, TxContextFieldTag.CalleeAddress) - storage_slot = instruction.stack_pop() + storage_key = instruction.stack_pop() new_value = instruction.stack_pop() - warm, _ = instruction.access_list_account_storage_read(tx_id, tx_callee_address, storage_slot) - current_value, _, txid, original_value = instruction.account_storage_read(tx_callee_address, storage_slot) + warm, _ = instruction.access_list_account_storage_read(tx_id, tx_callee_address, storage_key) + current_value, _, txid, original_value = instruction.account_storage_read(tx_callee_address, storage_key) instruction.constrain_equal(tx_id, txid) # TODO: Use intrinsic gas (EIP 2028, 2930) @@ -89,10 +89,10 @@ def sstore(instruction: Instruction): gas_refund = gas_refund + SSTORE_RESET_GAS - SLOAD_GAS instruction.account_storage_write_with_reversion( - tx_callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) instruction.add_account_storage_to_access_list_with_reversion( - tx_id, tx_callee_address, storage_slot, is_persistent, rw_counter_end_of_reversion + tx_id, tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) new_gas_refund, _ = instruction.tx_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) instruction.constrain_equal(gas_refund, new_gas_refund) diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index c14934ad9..77bd50c88 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -43,13 +43,13 @@ ) -@pytest.mark.parametrize("tx, slot_be_bytes, warm, result", TESTING_DATA) -def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): +@pytest.mark.parametrize("tx, storage_key_be_bytes, warm, result", TESTING_DATA) +def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: bool): randomness = rand_fp() - storage_slot = RLC(bytes(reversed(slot_be_bytes)), randomness) + storage_key = RLC(bytes(reversed(storage_key_be_bytes)), randomness) - bytecode = Bytecode().push32(slot_be_bytes).sload().stop() + bytecode = Bytecode().push32(storage_key_be_bytes).sload().stop() bytecode_hash = RLC(bytecode.hash(), randomness) value = 2 @@ -76,14 +76,14 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): 0, ), (11, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), - (12, RW.Read, RWTableTag.Stack, 1, 1023, 0, storage_slot, 0, 0, 0), + (12, RW.Read, RWTableTag.Stack, 1, 1023, 0, storage_key, 0, 0, 0), ( 13, RW.Read, RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, - storage_slot, + storage_key, 1 if warm else 0, 0, 0, @@ -94,7 +94,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): RW.Read, RWTableTag.AccountStorage, tx.callee_address, - storage_slot, + storage_key, 0, value, value_prev, @@ -107,7 +107,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, - storage_slot, + storage_key, 1, 1 if warm else 0, 0, @@ -125,7 +125,7 @@ def test_sload(tx: Transaction, slot_be_bytes: bytes, warm: bool, result: bool): RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, - storage_slot, + storage_key, 1 if warm else 0, 1, 0, diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index cf95364af..380cdfe2a 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -61,11 +61,11 @@ def gen_test_cases(): test_cases.append( ( Transaction(caller_address=rand_address(), callee_address=rand_address()), # tx - bytes([i for i in range(32, 0, -1)]), # storage_slot + bytes([i for i in range(32, 0, -1)]), # storage_key value_case[0], # new_value value_case[1], # value_prev_diff value_case[2], # original_value_diff - warm_case, # is_warm_storage_slot + warm_case, # is_warm_storage_key persist_case, # is_not_reverted ) ) @@ -76,11 +76,11 @@ def gen_test_cases(): @pytest.mark.parametrize( - "tx, slot_be_bytes, value_be_bytes, value_prev_be_bytes, original_value_be_bytes, warm, result", TESTING_DATA + "tx, storage_key_be_bytes, value_be_bytes, value_prev_be_bytes, original_value_be_bytes, warm, result", TESTING_DATA ) def test_sstore( tx: Transaction, - slot_be_bytes: bytes, + storage_key_be_bytes: bytes, value_be_bytes: bytes, value_prev_be_bytes: int, original_value_be_bytes: int, @@ -89,12 +89,12 @@ def test_sstore( ): randomness = rand_fp() - storage_slot = RLC(bytes(reversed(slot_be_bytes)), randomness) + storage_key = RLC(bytes(reversed(storage_key_be_bytes)), randomness) value = RLC(bytes(reversed(value_be_bytes)), randomness) value_prev = RLC(bytes(reversed(value_prev_be_bytes)), randomness) original_value = RLC(bytes(reversed(original_value_be_bytes)), randomness) - bytecode = Bytecode().push32(slot_be_bytes).push32(value_be_bytes).sstore().stop() + bytecode = Bytecode().push32(storage_key_be_bytes).push32(value_be_bytes).sstore().stop() bytecode_hash = RLC(bytecode.hash(), randomness) if value_prev == value: @@ -148,7 +148,7 @@ def test_sstore( 0, ), (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), - (4, RW.Read, RWTableTag.Stack, 1, 1022, 0, storage_slot, 0, 0, 0), + (4, RW.Read, RWTableTag.Stack, 1, 1022, 0, storage_key, 0, 0, 0), (5, RW.Read, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), ( 6, @@ -156,7 +156,7 @@ def test_sstore( RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, - storage_slot, + storage_key, 1 if warm else 0, 0, 0, @@ -167,7 +167,7 @@ def test_sstore( RW.Read, RWTableTag.AccountStorage, tx.callee_address, - storage_slot, + storage_key, 0, value_prev, original_value, @@ -180,7 +180,7 @@ def test_sstore( RW.Write, RWTableTag.AccountStorage, tx.callee_address, - storage_slot, + storage_key, 0, value, value_prev, @@ -193,7 +193,7 @@ def test_sstore( RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, - storage_slot, + storage_key, 1, 1 if warm else 0, 0, @@ -223,7 +223,7 @@ def test_sstore( RWTableTag.TxAccessListAccountStorage, tx.id, tx.callee_address, - storage_slot, + storage_key, 1 if warm else 0, 1, 0, @@ -234,7 +234,7 @@ def test_sstore( RW.Write, RWTableTag.AccountStorage, tx.callee_address, - storage_slot, + storage_key, 0, value_prev, value, From 807f607bb4898c84154609ea8830e62e29bbe738 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Wed, 26 Jan 2022 11:12:53 +0800 Subject: [PATCH 15/37] format .md --- specs/opcode/54SLOAD_55SSTORE.md | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/specs/opcode/54SLOAD_55SSTORE.md b/specs/opcode/54SLOAD_55SSTORE.md index c498fa63c..6396ce92b 100644 --- a/specs/opcode/54SLOAD_55SSTORE.md +++ b/specs/opcode/54SLOAD_55SSTORE.md @@ -20,46 +20,46 @@ - gc - `SLOAD`: +5 (2 stack operations + 1 storage reads + 2 access_list reads/writes) - `SSTORE`: +8 - + 2 stack operations - + 2 storage reads/writes - + 2 access_list reads/writes - + 2 gas_refund reads/writes + - 2 stack operations + - 2 storage reads/writes + - 2 access_list reads/writes + - 2 gas_refund reads/writes - stack_pointer - `SLOAD`: remains the same - `SSTORE`: -2 - pc + 1 - state_write_counter - - `SLOAD`: +1 (access_list) - - `SSTORE`: +3 (for storage, access_list & gas_refund respectively) + - `SLOAD`: +1 (access_list) + - `SSTORE`: +3 (for storage, access_list & gas_refund respectively) - gas: - `SLOAD`: - + the accessed address is warm: gas + WARM_STORAGE_READ_COST - + the accessed address is cold: gas + COLD_SLOAD_COST + - the accessed address is warm: gas + WARM_STORAGE_READ_COST + - the accessed address is cold: gas + COLD_SLOAD_COST - `SSTORE`: - + the accessed address is warm: - * `current_value == new_value`: gas + SLOAD_GAS - * `current_value != new_value`: + - the accessed address is warm: + - `current_value == new_value`: gas + SLOAD_GAS + - `current_value != new_value`: - `original_value == current_value`: - `original_value == 0`: gas + SSTORE_SET_GAS - `original_value != 0`: gas + SSTORE_RESET_GAS - `original_value != current_value`: gas + SLOAD_GAS - + the accessed address is cold: - * `current_value == new_value`: gas + SLOAD_GAS + COLD_SLOAD_COST - * `current_value != new_value`: + - the accessed address is cold: + - `current_value == new_value`: gas + SLOAD_GAS + COLD_SLOAD_COST + - `current_value != new_value`: - `original_value == current_value`: - `original_value == 0`: gas + SSTORE_SET_GAS + COLD_SLOAD_COST - `original_value != 0`: gas + SSTORE_RESET_GAS + COLD_SLOAD_COST - `original_value != current_value`: gas + SLOAD_GAS + COLD_SLOAD_COST * gas_refund: - `SSTORE`: - + `current_value != new_value`: - * `original_value == current_value`: - * `original_value != 0` && `new_value == 0`: gas_refund + SSTORE_CLEARS_SCHEDULE - * `original_value != current_value`: - * `original_value != 0`: + - `current_value != new_value`: + - `original_value == current_value`: + - `original_value != 0` && `new_value == 0`: gas_refund + SSTORE_CLEARS_SCHEDULE + - `original_value != current_value`: + - `original_value != 0`: - `current_value == 0`: gas_refund - SSTORE_CLEARS_SCHEDULE - `new_value == 0`: gas_refund + SSTORE_CLEARS_SCHEDULE - * `original_value == new_value`: + - `original_value == new_value`: - `original_value == 0`: gas_refund + SSTORE_SET_GAS - SLOAD_GAS - `original_value != 0`: gas_refund + SSTORE_RESET_GAS - SLOAD_GAS 3. lookups: @@ -78,8 +78,8 @@ - The 32 bytes of new `value` are written to storage at `address` - access_list: Whether the address is warm (accessed before), mark as warm afterward - gas_refund: - + Read the accumulated gas_refund for this tx - + Write the new accumulated gas_refund for this tx + - Read the accumulated gas_refund for this tx + - Write the new accumulated gas_refund for this tx ## Exceptions From 49bc579d776d506368d2a4cf968149e54d6f29b4 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Wed, 26 Jan 2022 11:18:08 +0800 Subject: [PATCH 16/37] fix --- tests/evm/test_sload.py | 2 +- tests/evm/test_sstore.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index 77bd50c88..ddf5651bd 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -12,7 +12,7 @@ Block, Bytecode, ) -from zkevm_specs.evm.execution.params import COLD_SLOAD_COST, WARM_STORAGE_READ_COST +from zkevm_specs.evm.execution.gas import COLD_SLOAD_COST, WARM_STORAGE_READ_COST from zkevm_specs.util import rand_fp, rand_address, RLC TESTING_DATA = ( diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index 380cdfe2a..f313feec8 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -12,7 +12,7 @@ Block, Bytecode, ) -from zkevm_specs.evm.execution.params import ( +from zkevm_specs.evm.execution.gas import ( COLD_SLOAD_COST, WARM_STORAGE_READ_COST, SLOAD_GAS, From d8b94003e9d1af161eb12c48e9399cecd81ec015 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Wed, 26 Jan 2022 20:45:24 +0800 Subject: [PATCH 17/37] better naming --- specs/opcode/54SLOAD_55SSTORE.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/specs/opcode/54SLOAD_55SSTORE.md b/specs/opcode/54SLOAD_55SSTORE.md index 6396ce92b..cdfc52371 100644 --- a/specs/opcode/54SLOAD_55SSTORE.md +++ b/specs/opcode/54SLOAD_55SSTORE.md @@ -33,17 +33,17 @@ - `SSTORE`: +3 (for storage, access_list & gas_refund respectively) - gas: - `SLOAD`: - - the accessed address is warm: gas + WARM_STORAGE_READ_COST - - the accessed address is cold: gas + COLD_SLOAD_COST + - the accessed `key` is warm: gas + WARM_STORAGE_READ_COST + - the accessed `key` is cold: gas + COLD_SLOAD_COST - `SSTORE`: - - the accessed address is warm: + - the accessed `key` is warm: - `current_value == new_value`: gas + SLOAD_GAS - `current_value != new_value`: - `original_value == current_value`: - `original_value == 0`: gas + SSTORE_SET_GAS - `original_value != 0`: gas + SSTORE_RESET_GAS - `original_value != current_value`: gas + SLOAD_GAS - - the accessed address is cold: + - the accessed `key` is cold: - `current_value == new_value`: gas + SLOAD_GAS + COLD_SLOAD_COST - `current_value != new_value`: - `original_value == current_value`: @@ -65,18 +65,18 @@ 3. lookups: - `SLOAD`: 5 busmapping lookups - stack: - - `address` is popped off the top of the stack + - `key` is popped off the top of the stack - `value` is pushed on top of the stack - - storage: The 32 bytes of `value` are read from storage at `address` - - access_list: Whether the address is warm (accessed before), mark as warm afterward + - storage: The 32 bytes of `value` are read from storage at `key` + - access_list: Whether the `key` is warm (accessed before), mark as warm afterward - `SSTORE`: 8 busmapping lookups - stack: - - `address` is popped off the top of the stack + - `key` is popped off the top of the stack - `value` is popped off the top of the stack - storage: - - Read the orignal_value and the current_value at `address` - - The 32 bytes of new `value` are written to storage at `address` - - access_list: Whether the address is warm (accessed before), mark as warm afterward + - Read the orignal_value and the current_value at `key` + - The 32 bytes of new `value` are written to storage at `key` + - access_list: Whether the `key` is warm (accessed before), mark as warm afterward - gas_refund: - Read the accumulated gas_refund for this tx - Write the new accumulated gas_refund for this tx From 7b2ef54fdaa2afdd4f75506e90fa5d4b887c5c3a Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Thu, 27 Jan 2022 12:34:17 +0800 Subject: [PATCH 18/37] fix --- tests/evm/test_gas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/evm/test_gas.py b/tests/evm/test_gas.py index 2ee8c31ae..e5b653d9a 100644 --- a/tests/evm/test_gas.py +++ b/tests/evm/test_gas.py @@ -38,7 +38,7 @@ def test_gas(gas: int): bytecode_table=set(bytecode.table_assignments(randomness)), rw_table=set( [ - (2, RW.Write, RWTableTag.Stack, 1, 1023, RLC(gas_left, randomness), 0, 0, 0), + (2, RW.Write, RWTableTag.Stack, 1, 1023, 0, RLC(gas_left, randomness), 0, 0, 0), ] ), ) From c74effdc14e7406591851978073eab798a810c67 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Thu, 27 Jan 2022 17:09:08 +0800 Subject: [PATCH 19/37] update markdown --- specs/opcode/54SLOAD_55SSTORE.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/specs/opcode/54SLOAD_55SSTORE.md b/specs/opcode/54SLOAD_55SSTORE.md index cdfc52371..e53220775 100644 --- a/specs/opcode/54SLOAD_55SSTORE.md +++ b/specs/opcode/54SLOAD_55SSTORE.md @@ -18,8 +18,13 @@ 2. opId === OpcodeId(0x55) for `SSTORE` 2. state transition: - gc - - `SLOAD`: +5 (2 stack operations + 1 storage reads + 2 access_list reads/writes) - - `SSTORE`: +8 + - `SLOAD`: +8 + - 3 call_context read + - 2 stack operations + - 1 storage reads + - 2 access_list reads/writes + - `SSTORE`: +11 + - 3 call_context read - 2 stack operations - 2 storage reads/writes - 2 access_list reads/writes @@ -63,13 +68,21 @@ - `original_value == 0`: gas_refund + SSTORE_SET_GAS - SLOAD_GAS - `original_value != 0`: gas_refund + SSTORE_RESET_GAS - SLOAD_GAS 3. lookups: - - `SLOAD`: 5 busmapping lookups + - `SLOAD`: 8 busmapping lookups + - call_context: + - `tx_id`: Read the `tx_id` for this tx. + - `rw_counter_end_of_reversion`: Read the `rw_counter_end` if this tx get reverted. + - `is_persistent`: Read if this tx will be reverted. - stack: - `key` is popped off the top of the stack - `value` is pushed on top of the stack - storage: The 32 bytes of `value` are read from storage at `key` - access_list: Whether the `key` is warm (accessed before), mark as warm afterward - - `SSTORE`: 8 busmapping lookups + - `SSTORE`: 11 busmapping lookups + - call_context: + - `tx_id`: Read the `tx_id` for this tx. + - `rw_counter_end_of_reversion`: Read the `rw_counter_end` if this tx get reverted. + - `is_persistent`: Read if this tx will be reverted. - stack: - `key` is popped off the top of the stack - `value` is popped off the top of the stack From 25373664bbcf03533080c8bd565feb6b35f4dcc5 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Thu, 27 Jan 2022 17:11:08 +0800 Subject: [PATCH 20/37] update python --- src/zkevm_specs/evm/execution/storage.py | 4 ++-- tests/evm/test_sload.py | 2 +- tests/evm/test_sstore.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 3dc683cdb..543cf6495 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -34,7 +34,7 @@ def sload(instruction: Instruction): instruction.step_state_transition_in_same_context( opcode, - rw_counter=Transition.delta(5), + rw_counter=Transition.delta(8), program_counter=Transition.delta(1), stack_pointer=Transition.delta(0), state_write_counter=Transition.delta(1), @@ -99,7 +99,7 @@ def sstore(instruction: Instruction): instruction.step_state_transition_in_same_context( opcode, - rw_counter=Transition.delta(8), + rw_counter=Transition.delta(11), program_counter=Transition.delta(1), stack_pointer=Transition.delta(2), state_write_counter=Transition.delta(3), diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index 38198d754..a97a2cb61 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -154,7 +154,7 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: ), StepState( execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, - rw_counter=14, + rw_counter=17, call_id=1, is_root=True, is_create=False, diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index 13229beea..b764b14bd 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -264,7 +264,7 @@ def test_sstore( ), StepState( execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, - rw_counter=9, + rw_counter=12, call_id=1, is_root=True, is_create=False, From a01a2d045f0835f0c05ff9e1c9d12a98feeb8221 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Thu, 10 Feb 2022 18:58:48 +0800 Subject: [PATCH 21/37] update markdown --- specs/opcode/54SLOAD_55SSTORE.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/specs/opcode/54SLOAD_55SSTORE.md b/specs/opcode/54SLOAD_55SSTORE.md index e53220775..3d3d65f4f 100644 --- a/specs/opcode/54SLOAD_55SSTORE.md +++ b/specs/opcode/54SLOAD_55SSTORE.md @@ -18,16 +18,16 @@ 2. opId === OpcodeId(0x55) for `SSTORE` 2. state transition: - gc - - `SLOAD`: +8 + - `SLOAD`: +7 - 3 call_context read - 2 stack operations - 1 storage reads - - 2 access_list reads/writes - - `SSTORE`: +11 + - 1 access_list write + - `SSTORE`: +10 - 3 call_context read - 2 stack operations - 2 storage reads/writes - - 2 access_list reads/writes + - 1 access_list write - 2 gas_refund reads/writes - stack_pointer - `SLOAD`: remains the same @@ -68,7 +68,7 @@ - `original_value == 0`: gas_refund + SSTORE_SET_GAS - SLOAD_GAS - `original_value != 0`: gas_refund + SSTORE_RESET_GAS - SLOAD_GAS 3. lookups: - - `SLOAD`: 8 busmapping lookups + - `SLOAD`: 7 busmapping lookups - call_context: - `tx_id`: Read the `tx_id` for this tx. - `rw_counter_end_of_reversion`: Read the `rw_counter_end` if this tx get reverted. @@ -77,8 +77,8 @@ - `key` is popped off the top of the stack - `value` is pushed on top of the stack - storage: The 32 bytes of `value` are read from storage at `key` - - access_list: Whether the `key` is warm (accessed before), mark as warm afterward - - `SSTORE`: 11 busmapping lookups + - access_list: Write as `true` for `key` + - `SSTORE`: 10 busmapping lookups - call_context: - `tx_id`: Read the `tx_id` for this tx. - `rw_counter_end_of_reversion`: Read the `rw_counter_end` if this tx get reverted. @@ -89,7 +89,7 @@ - storage: - Read the orignal_value and the current_value at `key` - The 32 bytes of new `value` are written to storage at `key` - - access_list: Whether the `key` is warm (accessed before), mark as warm afterward + - access_list: Write as `true` for `key` - gas_refund: - Read the accumulated gas_refund for this tx - Write the new accumulated gas_refund for this tx From 026ac286646b822b4404ca0fb2f6289cd43bd61d Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Thu, 10 Feb 2022 19:04:36 +0800 Subject: [PATCH 22/37] update sload codes --- src/zkevm_specs/evm/execution/storage.py | 13 +++++++------ src/zkevm_specs/evm/instruction.py | 21 ++++----------------- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 543cf6495..0bbf2a61a 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -21,20 +21,21 @@ def sload(instruction: Instruction): tx_callee_address = instruction.tx_context_lookup(tx_id, TxContextFieldTag.CalleeAddress) storage_key = instruction.stack_pop() - warm, _ = instruction.access_list_account_storage_read(tx_id, tx_callee_address, storage_key) - - # TODO: Use intrinsic gas (EIP 2028, 2930) - dynamic_gas_cost = WARM_STORAGE_READ_COST if warm else COLD_SLOAD_COST instruction.account_storage_read(tx_callee_address, storage_key) - instruction.add_account_storage_to_access_list_with_reversion( + + _, is_warm_prev = instruction.add_account_storage_to_access_list_with_reversion( tx_id, tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) + + # TODO: Use intrinsic gas (EIP 2028, 2930) + dynamic_gas_cost = WARM_STORAGE_READ_COST if warm else COLD_SLOAD_COST + instruction.stack_push() instruction.step_state_transition_in_same_context( opcode, - rw_counter=Transition.delta(8), + rw_counter=Transition.delta(7), program_counter=Transition.delta(1), stack_pointer=Transition.delta(0), state_write_counter=Transition.delta(1), diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index e4d0fa746..0ab80ab8f 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -574,31 +574,18 @@ def add_account_to_access_list_with_reversion( ) return row[-4] - row[-3] - def access_list_account_storage_read( - self, - tx_id: int, - account_address: int, - storage_key: int, - ) -> Tuple[int, int]: - row = self.rw_lookup( - RW.Read, - RWTableTag.TxAccessListAccountStorage, - [tx_id, account_address, storage_key], - ) - return row[-4], row[-3] - def add_account_storage_to_access_list( self, tx_id: int, account_address: int, storage_key: int, - ) -> bool: + ) -> Tuple[int, int]: row = self.rw_lookup( RW.Write, RWTableTag.TxAccessListAccountStorage, [tx_id, account_address, storage_key, 1], ) - return row[-4] - row[-3] + return row[-4], row[-3] def add_account_storage_to_access_list_with_reversion( self, @@ -608,7 +595,7 @@ def add_account_storage_to_access_list_with_reversion( is_persistent: bool, rw_counter_end_of_reversion: int, state_write_counter: Optional[int] = None, - ) -> bool: + ) -> Tuple[int, int]: row = self.state_write_with_reversion( RWTableTag.TxAccessListAccountStorage, [tx_id, account_address, storage_key, 1], @@ -616,7 +603,7 @@ def add_account_storage_to_access_list_with_reversion( rw_counter_end_of_reversion, state_write_counter, ) - return row[-4] - row[-3] + return row[-4], row[-3] def transfer_with_gas_fee( self, From c7e504e706333868b98cc76589e5e42dc0a89402 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Thu, 10 Feb 2022 19:09:13 +0800 Subject: [PATCH 23/37] update test_sload --- src/zkevm_specs/evm/execution/storage.py | 2 +- tests/evm/test_sload.py | 22 +++++----------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 0bbf2a61a..9a9fc1694 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -29,7 +29,7 @@ def sload(instruction: Instruction): ) # TODO: Use intrinsic gas (EIP 2028, 2930) - dynamic_gas_cost = WARM_STORAGE_READ_COST if warm else COLD_SLOAD_COST + dynamic_gas_cost = WARM_STORAGE_READ_COST if is_warm_prev else COLD_SLOAD_COST instruction.stack_push() diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index a97a2cb61..4ccadb287 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -70,7 +70,7 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: 1, CallContextFieldTag.RwCounterEndOfReversion, 0, - 0 if result else 19, + 0 if result else 18, 0, 0, 0, @@ -80,18 +80,6 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: ( 13, RW.Read, - RWTableTag.TxAccessListAccountStorage, - tx.id, - tx.callee_address, - storage_key, - 1 if warm else 0, - 0, - 0, - 0, - ), - ( - 14, - RW.Read, RWTableTag.AccountStorage, tx.callee_address, storage_key, @@ -102,7 +90,7 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: value_committed, ), ( - 15, + 14, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -113,14 +101,14 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: 0, 0, ), - (16, RW.Write, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), + (15, RW.Write, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), ] + ( [] if result else [ ( - 19, + 18, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -154,7 +142,7 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: ), StepState( execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, - rw_counter=17, + rw_counter=16, call_id=1, is_root=True, is_create=False, From ab5fc3c0d66563912d0561bef9a57ad9260ee14b Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Thu, 10 Feb 2022 19:19:46 +0800 Subject: [PATCH 24/37] update test_sstore --- src/zkevm_specs/evm/execution/storage.py | 53 ++++++++++++------------ tests/evm/test_sstore.py | 30 ++++---------- 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 9a9fc1694..ac35fc266 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -24,15 +24,15 @@ def sload(instruction: Instruction): instruction.account_storage_read(tx_callee_address, storage_key) - _, is_warm_prev = instruction.add_account_storage_to_access_list_with_reversion( + new_is_warm, is_warm = instruction.add_account_storage_to_access_list_with_reversion( tx_id, tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) - # TODO: Use intrinsic gas (EIP 2028, 2930) - dynamic_gas_cost = WARM_STORAGE_READ_COST if is_warm_prev else COLD_SLOAD_COST - instruction.stack_push() + # TODO: Use intrinsic gas (EIP 2028, 2930) + dynamic_gas_cost = WARM_STORAGE_READ_COST if is_warm else COLD_SLOAD_COST + instruction.step_state_transition_in_same_context( opcode, rw_counter=Transition.delta(7), @@ -54,23 +54,17 @@ def sstore(instruction: Instruction): storage_key = instruction.stack_pop() new_value = instruction.stack_pop() - warm, _ = instruction.access_list_account_storage_read(tx_id, tx_callee_address, storage_key) + current_value, _, txid, original_value = instruction.account_storage_read(tx_callee_address, storage_key) instruction.constrain_equal(tx_id, txid) - # TODO: Use intrinsic gas (EIP 2028, 2930) - if current_value == new_value: - dynamic_gas_cost = SLOAD_GAS - else: - if original_value == current_value: - if original_value == 0: - dynamic_gas_cost = SSTORE_SET_GAS - else: - dynamic_gas_cost = SSTORE_RESET_GAS - else: - dynamic_gas_cost = SLOAD_GAS - if not warm: - dynamic_gas_cost = dynamic_gas_cost + COLD_SLOAD_COST + instruction.account_storage_write_with_reversion( + tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion + ) + + new_is_warm, is_warm = instruction.add_account_storage_to_access_list_with_reversion( + tx_id, tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion + ) gas_refund = instruction.tx_refund_read(tx_id) if current_value != new_value: @@ -88,19 +82,26 @@ def sstore(instruction: Instruction): gas_refund = gas_refund + SSTORE_SET_GAS - SLOAD_GAS else: gas_refund = gas_refund + SSTORE_RESET_GAS - SLOAD_GAS - - instruction.account_storage_write_with_reversion( - tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion - ) - instruction.add_account_storage_to_access_list_with_reversion( - tx_id, tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion - ) new_gas_refund, _ = instruction.tx_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) instruction.constrain_equal(gas_refund, new_gas_refund) + # TODO: Use intrinsic gas (EIP 2028, 2930) + if current_value == new_value: + dynamic_gas_cost = SLOAD_GAS + else: + if original_value == current_value: + if original_value == 0: + dynamic_gas_cost = SSTORE_SET_GAS + else: + dynamic_gas_cost = SSTORE_RESET_GAS + else: + dynamic_gas_cost = SLOAD_GAS + if not is_warm: + dynamic_gas_cost = dynamic_gas_cost + COLD_SLOAD_COST + instruction.step_state_transition_in_same_context( opcode, - rw_counter=Transition.delta(11), + rw_counter=Transition.delta(10), program_counter=Transition.delta(1), stack_pointer=Transition.delta(2), state_write_counter=Transition.delta(3), diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index b764b14bd..7c334f9a2 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -142,7 +142,7 @@ def test_sstore( 1, CallContextFieldTag.RwCounterEndOfReversion, 0, - 0 if result else 16, + 0 if result else 15, 0, 0, 0, @@ -153,18 +153,6 @@ def test_sstore( ( 6, RW.Read, - RWTableTag.TxAccessListAccountStorage, - tx.id, - tx.callee_address, - storage_key, - 1 if warm else 0, - 0, - 0, - 0, - ), - ( - 7, - RW.Read, RWTableTag.AccountStorage, tx.callee_address, storage_key, @@ -174,9 +162,8 @@ def test_sstore( tx.id, original_value, ), - (8, RW.Read, RWTableTag.TxRefund, tx.id, 0, 0, old_gas_refund, 0, 0, 0), ( - 9, + 7, RW.Write, RWTableTag.AccountStorage, tx.callee_address, @@ -188,7 +175,7 @@ def test_sstore( original_value, ), ( - 10, + 8, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -199,14 +186,15 @@ def test_sstore( 0, 0, ), - (11, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), + (9, RW.Read, RWTableTag.TxRefund, tx.id, 0, 0, old_gas_refund, 0, 0, 0), + (10, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), ] + ( [] if result else [ ( - 14, + 13, RW.Write, RWTableTag.TxRefund, tx.id, @@ -218,7 +206,7 @@ def test_sstore( 0, ), ( - 15, + 14, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -230,7 +218,7 @@ def test_sstore( 0, ), ( - 16, + 15, RW.Write, RWTableTag.AccountStorage, tx.callee_address, @@ -264,7 +252,7 @@ def test_sstore( ), StepState( execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, - rw_counter=12, + rw_counter=11, call_id=1, is_root=True, is_create=False, From 5a284c0f8385cf6f28080c457dcbcaa62b656d9e Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Fri, 11 Feb 2022 11:51:40 +0800 Subject: [PATCH 25/37] change lookup for CalleeAddress from TxContextLookup to CallContextLookup --- specs/opcode/54SLOAD_55SSTORE.md | 14 +++++---- src/zkevm_specs/evm/execution/storage.py | 18 ++++++------ tests/evm/test_sload.py | 26 ++++++++++++----- tests/evm/test_sstore.py | 36 ++++++++++++++++-------- 4 files changed, 60 insertions(+), 34 deletions(-) diff --git a/specs/opcode/54SLOAD_55SSTORE.md b/specs/opcode/54SLOAD_55SSTORE.md index 3d3d65f4f..02cf50e2b 100644 --- a/specs/opcode/54SLOAD_55SSTORE.md +++ b/specs/opcode/54SLOAD_55SSTORE.md @@ -18,13 +18,13 @@ 2. opId === OpcodeId(0x55) for `SSTORE` 2. state transition: - gc - - `SLOAD`: +7 - - 3 call_context read + - `SLOAD`: +8 + - 4 call_context read - 2 stack operations - 1 storage reads - 1 access_list write - - `SSTORE`: +10 - - 3 call_context read + - `SSTORE`: +11 + - 4 call_context read - 2 stack operations - 2 storage reads/writes - 1 access_list write @@ -68,21 +68,23 @@ - `original_value == 0`: gas_refund + SSTORE_SET_GAS - SLOAD_GAS - `original_value != 0`: gas_refund + SSTORE_RESET_GAS - SLOAD_GAS 3. lookups: - - `SLOAD`: 7 busmapping lookups + - `SLOAD`: 8 busmapping lookups - call_context: - `tx_id`: Read the `tx_id` for this tx. - `rw_counter_end_of_reversion`: Read the `rw_counter_end` if this tx get reverted. - `is_persistent`: Read if this tx will be reverted. + - `callee_address`: Read the `callee_address` of this call. - stack: - `key` is popped off the top of the stack - `value` is pushed on top of the stack - storage: The 32 bytes of `value` are read from storage at `key` - access_list: Write as `true` for `key` - - `SSTORE`: 10 busmapping lookups + - `SSTORE`: 11 busmapping lookups - call_context: - `tx_id`: Read the `tx_id` for this tx. - `rw_counter_end_of_reversion`: Read the `rw_counter_end` if this tx get reverted. - `is_persistent`: Read if this tx will be reverted. + - `callee_address`: Read the `callee_address` of this call. - stack: - `key` is popped off the top of the stack - `value` is popped off the top of the stack diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index ac35fc266..4253449be 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -18,14 +18,14 @@ def sload(instruction: Instruction): 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) - tx_callee_address = instruction.tx_context_lookup(tx_id, TxContextFieldTag.CalleeAddress) + callee_address = instruction.call_context_lookup(CallContextFieldTag.CalleeAddress) storage_key = instruction.stack_pop() - instruction.account_storage_read(tx_callee_address, storage_key) + instruction.account_storage_read(callee_address, storage_key) new_is_warm, is_warm = instruction.add_account_storage_to_access_list_with_reversion( - tx_id, tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion + tx_id, callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) instruction.stack_push() @@ -35,7 +35,7 @@ def sload(instruction: Instruction): instruction.step_state_transition_in_same_context( opcode, - rw_counter=Transition.delta(7), + rw_counter=Transition.delta(8), program_counter=Transition.delta(1), stack_pointer=Transition.delta(0), state_write_counter=Transition.delta(1), @@ -50,20 +50,20 @@ def sstore(instruction: Instruction): 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) - tx_callee_address = instruction.tx_context_lookup(tx_id, TxContextFieldTag.CalleeAddress) + callee_address = instruction.call_context_lookup(CallContextFieldTag.CalleeAddress) storage_key = instruction.stack_pop() new_value = instruction.stack_pop() - current_value, _, txid, original_value = instruction.account_storage_read(tx_callee_address, storage_key) + current_value, _, txid, original_value = instruction.account_storage_read(callee_address, storage_key) instruction.constrain_equal(tx_id, txid) instruction.account_storage_write_with_reversion( - tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion + callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) new_is_warm, is_warm = instruction.add_account_storage_to_access_list_with_reversion( - tx_id, tx_callee_address, storage_key, is_persistent, rw_counter_end_of_reversion + tx_id, callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) gas_refund = instruction.tx_refund_read(tx_id) @@ -101,7 +101,7 @@ def sstore(instruction: Instruction): instruction.step_state_transition_in_same_context( opcode, - rw_counter=Transition.delta(10), + rw_counter=Transition.delta(11), program_counter=Transition.delta(1), stack_pointer=Transition.delta(2), state_write_counter=Transition.delta(3), diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index 4ccadb287..d3c2aea86 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -70,15 +70,27 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: 1, CallContextFieldTag.RwCounterEndOfReversion, 0, - 0 if result else 18, + 0 if result else 19, 0, 0, 0, ), (11, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), - (12, RW.Read, RWTableTag.Stack, 1, 1023, 0, storage_key, 0, 0, 0), ( - 13, + 12, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.CalleeAddress, + 0, + tx.callee_address, + 0, + 0, + 0, + ), + (13, RW.Read, RWTableTag.Stack, 1, 1023, 0, storage_key, 0, 0, 0), + ( + 14, RW.Read, RWTableTag.AccountStorage, tx.callee_address, @@ -90,7 +102,7 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: value_committed, ), ( - 14, + 15, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -101,14 +113,14 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: 0, 0, ), - (15, RW.Write, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), + (16, RW.Write, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), ] + ( [] if result else [ ( - 18, + 19, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -142,7 +154,7 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: ), StepState( execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, - rw_counter=16, + rw_counter=17, call_id=1, is_root=True, is_create=False, diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index 7c334f9a2..11c73981e 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -142,16 +142,28 @@ def test_sstore( 1, CallContextFieldTag.RwCounterEndOfReversion, 0, - 0 if result else 15, + 0 if result else 16, 0, 0, 0, ), (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), - (4, RW.Read, RWTableTag.Stack, 1, 1022, 0, storage_key, 0, 0, 0), - (5, RW.Read, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), ( - 6, + 4, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.CalleeAddress, + 0, + tx.callee_address, + 0, + 0, + 0, + ), + (5, RW.Read, RWTableTag.Stack, 1, 1022, 0, storage_key, 0, 0, 0), + (6, RW.Read, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), + ( + 7, RW.Read, RWTableTag.AccountStorage, tx.callee_address, @@ -163,7 +175,7 @@ def test_sstore( original_value, ), ( - 7, + 8, RW.Write, RWTableTag.AccountStorage, tx.callee_address, @@ -175,7 +187,7 @@ def test_sstore( original_value, ), ( - 8, + 9, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -186,15 +198,15 @@ def test_sstore( 0, 0, ), - (9, RW.Read, RWTableTag.TxRefund, tx.id, 0, 0, old_gas_refund, 0, 0, 0), - (10, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), + (10, RW.Read, RWTableTag.TxRefund, tx.id, 0, 0, old_gas_refund, 0, 0, 0), + (11, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), ] + ( [] if result else [ ( - 13, + 14, RW.Write, RWTableTag.TxRefund, tx.id, @@ -206,7 +218,7 @@ def test_sstore( 0, ), ( - 14, + 15, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -218,7 +230,7 @@ def test_sstore( 0, ), ( - 15, + 16, RW.Write, RWTableTag.AccountStorage, tx.callee_address, @@ -252,7 +264,7 @@ def test_sstore( ), StepState( execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, - rw_counter=11, + rw_counter=12, call_id=1, is_root=True, is_create=False, From 181e3e6c61f3a8bf6e9c750a95e50856cc80793c Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Sun, 13 Feb 2022 22:33:28 +0800 Subject: [PATCH 26/37] Update tx refund (#36) * update markdown * update python * update test --- specs/opcode/54SLOAD_55SSTORE.md | 7 +++---- src/zkevm_specs/evm/execution/storage.py | 16 ++++++++-------- tests/evm/test_sstore.py | 13 ++++++------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/specs/opcode/54SLOAD_55SSTORE.md b/specs/opcode/54SLOAD_55SSTORE.md index 02cf50e2b..24deba2e3 100644 --- a/specs/opcode/54SLOAD_55SSTORE.md +++ b/specs/opcode/54SLOAD_55SSTORE.md @@ -23,12 +23,12 @@ - 2 stack operations - 1 storage reads - 1 access_list write - - `SSTORE`: +11 + - `SSTORE`: +10 - 4 call_context read - 2 stack operations - 2 storage reads/writes - 1 access_list write - - 2 gas_refund reads/writes + - 1 gas_refund reads/writes - stack_pointer - `SLOAD`: remains the same - `SSTORE`: -2 @@ -79,7 +79,7 @@ - `value` is pushed on top of the stack - storage: The 32 bytes of `value` are read from storage at `key` - access_list: Write as `true` for `key` - - `SSTORE`: 11 busmapping lookups + - `SSTORE`: 10 busmapping lookups - call_context: - `tx_id`: Read the `tx_id` for this tx. - `rw_counter_end_of_reversion`: Read the `rw_counter_end` if this tx get reverted. @@ -93,7 +93,6 @@ - The 32 bytes of new `value` are written to storage at `key` - access_list: Write as `true` for `key` - gas_refund: - - Read the accumulated gas_refund for this tx - Write the new accumulated gas_refund for this tx ## Exceptions diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 4253449be..42492e6bc 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -66,23 +66,23 @@ def sstore(instruction: Instruction): tx_id, callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) - gas_refund = instruction.tx_refund_read(tx_id) + gas_refund, gas_refund_prev = instruction.tx_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) + new_gas_refund = gas_refund_prev if current_value != new_value: if original_value == current_value: if original_value != 0 and new_value == 0: - gas_refund = gas_refund + SSTORE_CLEARS_SCHEDULE + new_gas_refund = new_gas_refund + SSTORE_CLEARS_SCHEDULE else: if original_value != 0: if current_value == 0: - gas_refund = gas_refund - SSTORE_CLEARS_SCHEDULE + new_gas_refund = new_gas_refund - SSTORE_CLEARS_SCHEDULE if new_value == 0: - gas_refund = gas_refund + SSTORE_CLEARS_SCHEDULE + new_gas_refund = new_gas_refund + SSTORE_CLEARS_SCHEDULE if original_value == new_value: if original_value == 0: - gas_refund = gas_refund + SSTORE_SET_GAS - SLOAD_GAS + new_gas_refund = new_gas_refund + SSTORE_SET_GAS - SLOAD_GAS else: - gas_refund = gas_refund + SSTORE_RESET_GAS - SLOAD_GAS - new_gas_refund, _ = instruction.tx_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) + new_gas_refund = new_gas_refund + SSTORE_RESET_GAS - SLOAD_GAS instruction.constrain_equal(gas_refund, new_gas_refund) # TODO: Use intrinsic gas (EIP 2028, 2930) @@ -101,7 +101,7 @@ def sstore(instruction: Instruction): instruction.step_state_transition_in_same_context( opcode, - rw_counter=Transition.delta(11), + rw_counter=Transition.delta(10), program_counter=Transition.delta(1), stack_pointer=Transition.delta(2), state_write_counter=Transition.delta(3), diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index 11c73981e..7b6de1276 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -142,7 +142,7 @@ def test_sstore( 1, CallContextFieldTag.RwCounterEndOfReversion, 0, - 0 if result else 16, + 0 if result else 15, 0, 0, 0, @@ -198,15 +198,14 @@ def test_sstore( 0, 0, ), - (10, RW.Read, RWTableTag.TxRefund, tx.id, 0, 0, old_gas_refund, 0, 0, 0), - (11, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), + (10, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), ] + ( [] if result else [ ( - 14, + 13, RW.Write, RWTableTag.TxRefund, tx.id, @@ -218,7 +217,7 @@ def test_sstore( 0, ), ( - 15, + 14, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -230,7 +229,7 @@ def test_sstore( 0, ), ( - 16, + 15, RW.Write, RWTableTag.AccountStorage, tx.callee_address, @@ -264,7 +263,7 @@ def test_sstore( ), StepState( execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, - rw_counter=12, + rw_counter=11, call_id=1, is_root=True, is_create=False, From 715a3ba3f55907db3e68e0fd74872180b1dda199 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Sun, 13 Feb 2022 22:34:16 +0800 Subject: [PATCH 27/37] format codes --- src/zkevm_specs/evm/execution/storage.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 42492e6bc..e377ca4fd 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -66,7 +66,9 @@ def sstore(instruction: Instruction): tx_id, callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) - gas_refund, gas_refund_prev = instruction.tx_refund_write_with_reversion(tx_id, is_persistent, rw_counter_end_of_reversion) + gas_refund, gas_refund_prev = instruction.tx_refund_write_with_reversion( + tx_id, is_persistent, rw_counter_end_of_reversion + ) new_gas_refund = gas_refund_prev if current_value != new_value: if original_value == current_value: From 0cf9a92ce7c1a6aefbf633c0b67c67cfad362391 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Tue, 15 Feb 2022 11:05:07 +0800 Subject: [PATCH 28/37] improve --- specs/opcode/54SLOAD_55SSTORE.md | 11 +++--- src/zkevm_specs/evm/execution/storage.py | 44 +++++++++++------------- src/zkevm_specs/evm/instruction.py | 4 +-- tests/evm/test_sstore.py | 26 ++++---------- 4 files changed, 35 insertions(+), 50 deletions(-) diff --git a/specs/opcode/54SLOAD_55SSTORE.md b/specs/opcode/54SLOAD_55SSTORE.md index 24deba2e3..7fde3c6f6 100644 --- a/specs/opcode/54SLOAD_55SSTORE.md +++ b/specs/opcode/54SLOAD_55SSTORE.md @@ -23,12 +23,12 @@ - 2 stack operations - 1 storage reads - 1 access_list write - - `SSTORE`: +10 + - `SSTORE`: +9 - 4 call_context read - 2 stack operations - - 2 storage reads/writes + - 1 storage reads/writes - 1 access_list write - - 1 gas_refund reads/writes + - 1 gas_refund writes - stack_pointer - `SLOAD`: remains the same - `SSTORE`: -2 @@ -79,7 +79,7 @@ - `value` is pushed on top of the stack - storage: The 32 bytes of `value` are read from storage at `key` - access_list: Write as `true` for `key` - - `SSTORE`: 10 busmapping lookups + - `SSTORE`: 9 busmapping lookups - call_context: - `tx_id`: Read the `tx_id` for this tx. - `rw_counter_end_of_reversion`: Read the `rw_counter_end` if this tx get reverted. @@ -89,8 +89,7 @@ - `key` is popped off the top of the stack - `value` is popped off the top of the stack - storage: - - Read the orignal_value and the current_value at `key` - - The 32 bytes of new `value` are written to storage at `key` + - The 32 bytes of new `value` are written to storage at `key`, with the previous `value` and `committed_value` - access_list: Write as `true` for `key` - gas_refund: - Write the new accumulated gas_refund for this tx diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index e377ca4fd..b259b9c70 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -24,7 +24,7 @@ def sload(instruction: Instruction): instruction.account_storage_read(callee_address, storage_key) - new_is_warm, is_warm = instruction.add_account_storage_to_access_list_with_reversion( + is_warm_new, is_warm = instruction.add_account_storage_to_access_list_with_reversion( tx_id, callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) @@ -53,45 +53,43 @@ def sstore(instruction: Instruction): callee_address = instruction.call_context_lookup(CallContextFieldTag.CalleeAddress) storage_key = instruction.stack_pop() - new_value = instruction.stack_pop() + value_new = instruction.stack_pop() - current_value, _, txid, original_value = instruction.account_storage_read(callee_address, storage_key) - instruction.constrain_equal(tx_id, txid) - - instruction.account_storage_write_with_reversion( + _, value_prev, txid, original_value = instruction.account_storage_write_with_reversion( callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) + instruction.constrain_equal(tx_id, txid) - new_is_warm, is_warm = instruction.add_account_storage_to_access_list_with_reversion( + is_warm_new, is_warm = instruction.add_account_storage_to_access_list_with_reversion( tx_id, callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) gas_refund, gas_refund_prev = instruction.tx_refund_write_with_reversion( tx_id, is_persistent, rw_counter_end_of_reversion ) - new_gas_refund = gas_refund_prev - if current_value != new_value: - if original_value == current_value: - if original_value != 0 and new_value == 0: - new_gas_refund = new_gas_refund + SSTORE_CLEARS_SCHEDULE + gas_refund_new = gas_refund_prev + if value_prev != value_new: + if original_value == value_prev: + if original_value != 0 and value_new == 0: + gas_refund_new = gas_refund_new + SSTORE_CLEARS_SCHEDULE else: if original_value != 0: - if current_value == 0: - new_gas_refund = new_gas_refund - SSTORE_CLEARS_SCHEDULE - if new_value == 0: - new_gas_refund = new_gas_refund + SSTORE_CLEARS_SCHEDULE - if original_value == new_value: + if value_prev == 0: + gas_refund_new = gas_refund_new - SSTORE_CLEARS_SCHEDULE + if value_new == 0: + gas_refund_new = gas_refund_new + SSTORE_CLEARS_SCHEDULE + if original_value == value_new: if original_value == 0: - new_gas_refund = new_gas_refund + SSTORE_SET_GAS - SLOAD_GAS + gas_refund_new = gas_refund_new + SSTORE_SET_GAS - SLOAD_GAS else: - new_gas_refund = new_gas_refund + SSTORE_RESET_GAS - SLOAD_GAS - instruction.constrain_equal(gas_refund, new_gas_refund) + gas_refund_new = gas_refund_new + SSTORE_RESET_GAS - SLOAD_GAS + instruction.constrain_equal(gas_refund, gas_refund_new) # TODO: Use intrinsic gas (EIP 2028, 2930) - if current_value == new_value: + if value_prev == value_new: dynamic_gas_cost = SLOAD_GAS else: - if original_value == current_value: + if original_value == value_prev: if original_value == 0: dynamic_gas_cost = SSTORE_SET_GAS else: @@ -103,7 +101,7 @@ def sstore(instruction: Instruction): instruction.step_state_transition_in_same_context( opcode, - rw_counter=Transition.delta(10), + rw_counter=Transition.delta(9), program_counter=Transition.delta(1), stack_pointer=Transition.delta(2), state_write_counter=Transition.delta(3), diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index 502732104..ea364e8b4 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -526,7 +526,7 @@ def account_storage_write_with_reversion( is_persistent: bool, rw_counter_end_of_reversion: int, state_write_counter: Optional[int] = None, - ) -> Tuple[int, int]: + ) -> Tuple[int, int, int, int]: row = self.state_write_with_reversion( RWTableTag.AccountStorage, [account_address, storage_key], @@ -534,7 +534,7 @@ def account_storage_write_with_reversion( rw_counter_end_of_reversion, state_write_counter, ) - return row[-4], row[-3] + return row[-4], row[-3], row[-2], row[-1] def add_account_to_access_list( self, diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index 7b6de1276..f28f957e3 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -142,7 +142,7 @@ def test_sstore( 1, CallContextFieldTag.RwCounterEndOfReversion, 0, - 0 if result else 15, + 0 if result else 14, 0, 0, 0, @@ -164,18 +164,6 @@ def test_sstore( (6, RW.Read, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), ( 7, - RW.Read, - RWTableTag.AccountStorage, - tx.callee_address, - storage_key, - 0, - value_prev, - original_value, - tx.id, - original_value, - ), - ( - 8, RW.Write, RWTableTag.AccountStorage, tx.callee_address, @@ -187,7 +175,7 @@ def test_sstore( original_value, ), ( - 9, + 8, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -198,14 +186,14 @@ def test_sstore( 0, 0, ), - (10, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), + (9, RW.Write, RWTableTag.TxRefund, tx.id, 0, 0, gas_refund, old_gas_refund, 0, 0), ] + ( [] if result else [ ( - 13, + 12, RW.Write, RWTableTag.TxRefund, tx.id, @@ -217,7 +205,7 @@ def test_sstore( 0, ), ( - 14, + 13, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -229,7 +217,7 @@ def test_sstore( 0, ), ( - 15, + 14, RW.Write, RWTableTag.AccountStorage, tx.callee_address, @@ -263,7 +251,7 @@ def test_sstore( ), StepState( execution_state=ExecutionState.STOP if result else ExecutionState.REVERT, - rw_counter=11, + rw_counter=10, call_id=1, is_root=True, is_create=False, From 58028bc2eb0ded3b65417ed9fcca173d3223a21f Mon Sep 17 00:00:00 2001 From: Steven Gu Date: Wed, 16 Feb 2022 17:16:10 +0800 Subject: [PATCH 29/37] Fix to FQ (from int) as PR-109. --- src/zkevm_specs/evm/execution/storage.py | 4 ++-- src/zkevm_specs/evm/instruction.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index b259b9c70..4ff0b9795 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -31,7 +31,7 @@ def sload(instruction: Instruction): instruction.stack_push() # TODO: Use intrinsic gas (EIP 2028, 2930) - dynamic_gas_cost = WARM_STORAGE_READ_COST if is_warm else COLD_SLOAD_COST + dynamic_gas_cost = WARM_STORAGE_READ_COST if is_warm == 1 else COLD_SLOAD_COST instruction.step_state_transition_in_same_context( opcode, @@ -96,7 +96,7 @@ def sstore(instruction: Instruction): dynamic_gas_cost = SSTORE_RESET_GAS else: dynamic_gas_cost = SLOAD_GAS - if not is_warm: + if is_warm == 0: dynamic_gas_cost = dynamic_gas_cost + COLD_SLOAD_COST instruction.step_state_transition_in_same_context( diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index d8963aac6..607227e85 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -447,7 +447,7 @@ def tx_refund_write_with_reversion( is_persistent: bool, rw_counter_end_of_reversion: int, state_write_counter: Optional[int] = None, - ) -> Tuple[int, int]: + ) -> Tuple[FQ, FQ]: row = self.state_write_with_reversion( RWTableTag.TxRefund, [tx_id], @@ -555,7 +555,7 @@ def account_storage_write_with_reversion( is_persistent: bool, rw_counter_end_of_reversion: int, state_write_counter: Optional[int] = None, - ) -> Tuple[int, int, int, int]: + ) -> Tuple[FQ, FQ, FQ, FQ]: row = self.state_write_with_reversion( RWTableTag.AccountStorage, [account_address, storage_key], @@ -615,7 +615,7 @@ def add_account_storage_to_access_list_with_reversion( is_persistent: bool, rw_counter_end_of_reversion: int, state_write_counter: Optional[int] = None, - ) -> Tuple[int, int]: + ) -> Tuple[FQ, FQ]: row = self.state_write_with_reversion( RWTableTag.TxAccessListAccountStorage, [tx_id, account_address, storage_key, 1], From fabec716ed81fd4a9e0d4067acaf5bdb057291bf Mon Sep 17 00:00:00 2001 From: Steven Gu Date: Thu, 17 Feb 2022 10:07:33 +0800 Subject: [PATCH 30/37] Fix to return FQ for some functions in `instruction.py`, and run `make fmt`. --- src/zkevm_specs/evm/execution/storage.py | 8 ++++-- src/zkevm_specs/evm/instruction.py | 12 ++++----- tests/evm/test_sload.py | 26 +++++++++++++++++-- tests/evm/test_sstore.py | 33 +++++++++++++++++++++--- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 4ff0b9795..c46bf93c8 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -16,7 +16,9 @@ def sload(instruction: Instruction): instruction.constrain_equal(opcode, Opcode.SLOAD) tx_id = instruction.call_context_lookup(CallContextFieldTag.TxId) - rw_counter_end_of_reversion = instruction.call_context_lookup(CallContextFieldTag.RwCounterEndOfReversion) + rw_counter_end_of_reversion = instruction.call_context_lookup( + CallContextFieldTag.RwCounterEndOfReversion + ) is_persistent = instruction.call_context_lookup(CallContextFieldTag.IsPersistent) callee_address = instruction.call_context_lookup(CallContextFieldTag.CalleeAddress) @@ -48,7 +50,9 @@ def sstore(instruction: Instruction): instruction.constrain_equal(opcode, Opcode.SSTORE) tx_id = instruction.call_context_lookup(CallContextFieldTag.TxId) - rw_counter_end_of_reversion = instruction.call_context_lookup(CallContextFieldTag.RwCounterEndOfReversion) + rw_counter_end_of_reversion = instruction.call_context_lookup( + CallContextFieldTag.RwCounterEndOfReversion + ) is_persistent = instruction.call_context_lookup(CallContextFieldTag.IsPersistent) callee_address = instruction.call_context_lookup(CallContextFieldTag.CalleeAddress) diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index 607227e85..bb629456b 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -221,7 +221,7 @@ def pair_select(self, value: int, lhs: int, rhs: int) -> Tuple[bool, bool]: def constant_divmod( self, numerator: IntOrFQ, denominator: IntOrFQ, n_bytes: int - ) -> Tuple[int, int]: + ) -> Tuple[FQ, FQ]: quotient, remainder = divmod(FQ(numerator).n, FQ(denominator).n) quotient, remainder = FQ(quotient), FQ(remainder) self.bytes_range_lookup(quotient, n_bytes) @@ -409,7 +409,7 @@ def state_write_with_reversion( def call_context_lookup( self, field_tag: CallContextFieldTag, rw: RW = RW.Read, call_id: Optional[int] = None - ) -> int: + ) -> FQ: if call_id is None: call_id = self.curr.call_id @@ -544,7 +544,7 @@ def sub_balance_with_reversion( self.constrain_zero(carry) return balance, balance_prev - def account_storage_read(self, account_address: int, storage_key: int) -> Tuple[int, int, int, int]: + def account_storage_read(self, account_address: int, storage_key: int) -> Tuple[FQ, FQ, FQ, FQ]: row = self.rw_lookup(RW.Read, RWTableTag.AccountStorage, [account_address, storage_key, 0]) return row[-4], row[-3], row[-2], row[-1] @@ -599,7 +599,7 @@ def add_account_storage_to_access_list( tx_id: int, account_address: int, storage_key: int, - ) -> Tuple[int, int]: + ) -> Tuple[FQ, FQ]: row = self.rw_lookup( RW.Write, RWTableTag.TxAccessListAccountStorage, @@ -633,7 +633,7 @@ def transfer_with_gas_fee( gas_fee: int, is_persistent: bool, rw_counter_end_of_reversion: int, - ) -> Tuple[Tuple[int, int], Tuple[int, int]]: + ) -> Tuple[Tuple[FQ, FQ], Tuple[FQ, FQ]]: sender_balance_pair = self.sub_balance_with_reversion( sender_address, [value, gas_fee], @@ -656,7 +656,7 @@ def transfer( is_persistent: bool, rw_counter_end_of_reversion: int, state_write_counter: Optional[int] = None, - ) -> Tuple[Tuple[int, int], Tuple[int, int]]: + ) -> Tuple[Tuple[FQ, FQ], Tuple[FQ, FQ]]: sender_balance_pair = self.sub_balance_with_reversion( sender_address, [value], diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index d3c2aea86..02f64f0df 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -62,7 +62,18 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: bytecode_table=set(bytecode.table_assignments(randomness)), rw_table=set( [ - (9, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, tx.id, 0, 0, 0), + ( + 9, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.TxId, + 0, + tx.id, + 0, + 0, + 0, + ), ( 10, RW.Read, @@ -75,7 +86,18 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: 0, 0, ), - (11, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), + ( + 11, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.IsPersistent, + 0, + result, + 0, + 0, + 0, + ), ( 12, RW.Read, diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index f28f957e3..5c8785742 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -60,7 +60,9 @@ def gen_test_cases(): for persist_case in persist_cases: test_cases.append( ( - Transaction(caller_address=rand_address(), callee_address=rand_address()), # tx + Transaction( + caller_address=rand_address(), callee_address=rand_address() + ), # tx bytes([i for i in range(32, 0, -1)]), # storage_key value_case[0], # new_value value_case[1], # value_prev_diff @@ -76,7 +78,8 @@ def gen_test_cases(): @pytest.mark.parametrize( - "tx, storage_key_be_bytes, value_be_bytes, value_prev_be_bytes, original_value_be_bytes, warm, result", TESTING_DATA + "tx, storage_key_be_bytes, value_be_bytes, value_prev_be_bytes, original_value_be_bytes, warm, result", + TESTING_DATA, ) def test_sstore( tx: Transaction, @@ -134,7 +137,18 @@ def test_sstore( bytecode_table=set(bytecode.table_assignments(randomness)), rw_table=set( [ - (1, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.TxId, 0, tx.id, 0, 0, 0), + ( + 1, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.TxId, + 0, + tx.id, + 0, + 0, + 0, + ), ( 2, RW.Read, @@ -147,7 +161,18 @@ def test_sstore( 0, 0, ), - (3, RW.Read, RWTableTag.CallContext, 1, CallContextFieldTag.IsPersistent, 0, result, 0, 0, 0), + ( + 3, + RW.Read, + RWTableTag.CallContext, + 1, + CallContextFieldTag.IsPersistent, + 0, + result, + 0, + 0, + 0, + ), ( 4, RW.Read, From 49cc2e73172089f3751849244847351e9c0a3624 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Fri, 18 Feb 2022 10:45:54 +0800 Subject: [PATCH 31/37] remove "intrinsic gas" comments Co-authored-by: Han --- src/zkevm_specs/evm/execution/storage.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index c46bf93c8..de6124d7b 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -32,7 +32,6 @@ def sload(instruction: Instruction): instruction.stack_push() - # TODO: Use intrinsic gas (EIP 2028, 2930) dynamic_gas_cost = WARM_STORAGE_READ_COST if is_warm == 1 else COLD_SLOAD_COST instruction.step_state_transition_in_same_context( @@ -89,7 +88,6 @@ def sstore(instruction: Instruction): gas_refund_new = gas_refund_new + SSTORE_RESET_GAS - SLOAD_GAS instruction.constrain_equal(gas_refund, gas_refund_new) - # TODO: Use intrinsic gas (EIP 2028, 2930) if value_prev == value_new: dynamic_gas_cost = SLOAD_GAS else: From 797689900e98f6261ccbcd92056ba4f400aa6e5a Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Fri, 18 Feb 2022 11:54:05 +0800 Subject: [PATCH 32/37] update account_storage_read, use tx_id, enforce following stak_push --- src/zkevm_specs/evm/execution/storage.py | 7 ++++--- src/zkevm_specs/evm/instruction.py | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index de6124d7b..01181c2e4 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -24,14 +24,15 @@ def sload(instruction: Instruction): storage_key = instruction.stack_pop() - instruction.account_storage_read(callee_address, storage_key) + instruction.constrain_equal( + instruction.account_storage_read(callee_address, storage_key, tx_id), + instruction.stack_push(), + ) is_warm_new, is_warm = instruction.add_account_storage_to_access_list_with_reversion( tx_id, callee_address, storage_key, is_persistent, rw_counter_end_of_reversion ) - instruction.stack_push() - dynamic_gas_cost = WARM_STORAGE_READ_COST if is_warm == 1 else COLD_SLOAD_COST instruction.step_state_transition_in_same_context( diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index 263778b99..cb966faee 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -543,9 +543,9 @@ def sub_balance_with_reversion( self.constrain_zero(carry) return balance, balance_prev - def account_storage_read(self, account_address: int, storage_key: int) -> Tuple[FQ, FQ, FQ, FQ]: - row = self.rw_lookup(RW.Read, RWTableTag.AccountStorage, [account_address, storage_key, 0]) - return row[-4], row[-3], row[-2], row[-1] + def account_storage_read(self, account_address: int, storage_key: int, tx_id: int) -> FQ: + row = self.rw_lookup(RW.Read, RWTableTag.AccountStorage, [account_address, storage_key, 0, Tables._, Tables._, tx_id]) + return row[-4] def account_storage_write_with_reversion( self, From 1342c12c5fed348d8b41969bea0ebdb6e46ee498 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Fri, 18 Feb 2022 11:56:05 +0800 Subject: [PATCH 33/37] fix test_sload --- src/zkevm_specs/evm/instruction.py | 6 +++++- tests/evm/test_sload.py | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index cb966faee..09d0d1113 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -544,7 +544,11 @@ def sub_balance_with_reversion( return balance, balance_prev def account_storage_read(self, account_address: int, storage_key: int, tx_id: int) -> FQ: - row = self.rw_lookup(RW.Read, RWTableTag.AccountStorage, [account_address, storage_key, 0, Tables._, Tables._, tx_id]) + row = self.rw_lookup( + RW.Read, + RWTableTag.AccountStorage, + [account_address, storage_key, 0, Tables._, Tables._, tx_id], + ) return row[-4] def account_storage_write_with_reversion( diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index 02f64f0df..a48a104f1 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -123,8 +123,9 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: tx.id, value_committed, ), + (15, RW.Write, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), ( - 15, + 16, RW.Write, RWTableTag.TxAccessListAccountStorage, tx.id, @@ -135,7 +136,6 @@ def test_sload(tx: Transaction, storage_key_be_bytes: bytes, warm: bool, result: 0, 0, ), - (16, RW.Write, RWTableTag.Stack, 1, 1023, 0, value, 0, 0, 0), ] + ( [] From e889c47090a0d5aadd57dc797d2483c193143cb7 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Fri, 18 Feb 2022 12:44:44 +0800 Subject: [PATCH 34/37] move storage_gas to param.py --- src/zkevm_specs/evm/execution/storage.py | 2 +- src/zkevm_specs/evm/execution/storage_gas.py | 6 ------ src/zkevm_specs/util/param.py | 8 ++++++++ tests/evm/test_sload.py | 2 +- tests/evm/test_sstore.py | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) delete mode 100644 src/zkevm_specs/evm/execution/storage_gas.py diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 01181c2e4..11af926ff 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -1,7 +1,7 @@ from ..instruction import Instruction, Transition from ..opcode import Opcode from ..table import CallContextFieldTag, TxContextFieldTag -from .storage_gas import ( +from ...util.param import ( COLD_SLOAD_COST, WARM_STORAGE_READ_COST, SLOAD_GAS, diff --git a/src/zkevm_specs/evm/execution/storage_gas.py b/src/zkevm_specs/evm/execution/storage_gas.py deleted file mode 100644 index 6904f7db3..000000000 --- a/src/zkevm_specs/evm/execution/storage_gas.py +++ /dev/null @@ -1,6 +0,0 @@ -COLD_SLOAD_COST = 2100 -WARM_STORAGE_READ_COST = 100 -SLOAD_GAS = 100 -SSTORE_SET_GAS = 20000 -SSTORE_RESET_GAS = 2900 -SSTORE_CLEARS_SCHEDULE = 15000 diff --git a/src/zkevm_specs/util/param.py b/src/zkevm_specs/util/param.py index b27bcc62c..32011d672 100644 --- a/src/zkevm_specs/util/param.py +++ b/src/zkevm_specs/util/param.py @@ -68,3 +68,11 @@ MEMORY_EXPANSION_QUAD_DENOMINATOR = 512 # Coefficient of linear part of memory expansion gas cost MEMORY_EXPANSION_LINEAR_COEFF = 3 + + +COLD_SLOAD_COST = 2100 +WARM_STORAGE_READ_COST = 100 +SLOAD_GAS = 100 +SSTORE_SET_GAS = 20000 +SSTORE_RESET_GAS = 2900 +SSTORE_CLEARS_SCHEDULE = 15000 diff --git a/tests/evm/test_sload.py b/tests/evm/test_sload.py index a48a104f1..a575cdfff 100644 --- a/tests/evm/test_sload.py +++ b/tests/evm/test_sload.py @@ -12,7 +12,7 @@ Block, Bytecode, ) -from zkevm_specs.evm.execution.storage_gas import COLD_SLOAD_COST, WARM_STORAGE_READ_COST +from zkevm_specs.util.param import COLD_SLOAD_COST, WARM_STORAGE_READ_COST from zkevm_specs.util import rand_fp, rand_address, RLC TESTING_DATA = ( diff --git a/tests/evm/test_sstore.py b/tests/evm/test_sstore.py index 5c8785742..0d11ab7c2 100644 --- a/tests/evm/test_sstore.py +++ b/tests/evm/test_sstore.py @@ -12,7 +12,7 @@ Block, Bytecode, ) -from zkevm_specs.evm.execution.storage_gas import ( +from zkevm_specs.util.param import ( COLD_SLOAD_COST, WARM_STORAGE_READ_COST, SLOAD_GAS, From 066a7431218a107826f46763052a27dc2fbd9fa5 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Fri, 18 Feb 2022 12:48:03 +0800 Subject: [PATCH 35/37] fix --- src/zkevm_specs/evm/execution/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zkevm_specs/evm/execution/__init__.py b/src/zkevm_specs/evm/execution/__init__.py index e4bec552b..be699cbec 100644 --- a/src/zkevm_specs/evm/execution/__init__.py +++ b/src/zkevm_specs/evm/execution/__init__.py @@ -23,7 +23,6 @@ from .gas import * from .gasprice import * from .storage import * -from .storage_gas import * from .selfbalance import * From 2b7e16efd801becf2878d4c4c316494057560ed9 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Fri, 18 Feb 2022 13:03:55 +0800 Subject: [PATCH 36/37] update account_storage_write_with_reversion, use tx_id, constrain value equal --- src/zkevm_specs/evm/execution/storage.py | 19 +++++++++---------- src/zkevm_specs/evm/instruction.py | 7 ++++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/zkevm_specs/evm/execution/storage.py b/src/zkevm_specs/evm/execution/storage.py index 11af926ff..e96f7a832 100644 --- a/src/zkevm_specs/evm/execution/storage.py +++ b/src/zkevm_specs/evm/execution/storage.py @@ -57,12 +57,11 @@ def sstore(instruction: Instruction): callee_address = instruction.call_context_lookup(CallContextFieldTag.CalleeAddress) storage_key = instruction.stack_pop() - value_new = instruction.stack_pop() - - _, value_prev, txid, original_value = instruction.account_storage_write_with_reversion( - callee_address, storage_key, is_persistent, rw_counter_end_of_reversion + storage_value = instruction.stack_pop() + value, value_prev, original_value = instruction.account_storage_write_with_reversion( + callee_address, storage_key, tx_id, is_persistent, rw_counter_end_of_reversion ) - instruction.constrain_equal(tx_id, txid) + instruction.constrain_equal(storage_value, value) is_warm_new, is_warm = instruction.add_account_storage_to_access_list_with_reversion( tx_id, callee_address, storage_key, is_persistent, rw_counter_end_of_reversion @@ -72,24 +71,24 @@ def sstore(instruction: Instruction): tx_id, is_persistent, rw_counter_end_of_reversion ) gas_refund_new = gas_refund_prev - if value_prev != value_new: + if value_prev != value: if original_value == value_prev: - if original_value != 0 and value_new == 0: + if original_value != 0 and value == 0: gas_refund_new = gas_refund_new + SSTORE_CLEARS_SCHEDULE else: if original_value != 0: if value_prev == 0: gas_refund_new = gas_refund_new - SSTORE_CLEARS_SCHEDULE - if value_new == 0: + if value == 0: gas_refund_new = gas_refund_new + SSTORE_CLEARS_SCHEDULE - if original_value == value_new: + if original_value == value: if original_value == 0: gas_refund_new = gas_refund_new + SSTORE_SET_GAS - SLOAD_GAS else: gas_refund_new = gas_refund_new + SSTORE_RESET_GAS - SLOAD_GAS instruction.constrain_equal(gas_refund, gas_refund_new) - if value_prev == value_new: + if value_prev == value: dynamic_gas_cost = SLOAD_GAS else: if original_value == value_prev: diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index 09d0d1113..b9ea92434 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -555,18 +555,19 @@ def account_storage_write_with_reversion( self, account_address: int, storage_key: int, + tx_id: int, is_persistent: bool, rw_counter_end_of_reversion: int, state_write_counter: Optional[int] = None, - ) -> Tuple[FQ, FQ, FQ, FQ]: + ) -> Tuple[FQ, FQ, FQ]: row = self.state_write_with_reversion( RWTableTag.AccountStorage, - [account_address, storage_key], + [account_address, storage_key, Tables._, Tables._, Tables._, tx_id], is_persistent, rw_counter_end_of_reversion, state_write_counter, ) - return row[-4], row[-3], row[-2], row[-1] + return row[-4], row[-3], row[-1] def add_account_to_access_list( self, From 7459dd3ea7df7bc2c008b759f91049dac97664a7 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ Date: Fri, 18 Feb 2022 13:04:59 +0800 Subject: [PATCH 37/37] fix --- src/zkevm_specs/evm/instruction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zkevm_specs/evm/instruction.py b/src/zkevm_specs/evm/instruction.py index b9ea92434..d37b1c4a8 100644 --- a/src/zkevm_specs/evm/instruction.py +++ b/src/zkevm_specs/evm/instruction.py @@ -562,7 +562,7 @@ def account_storage_write_with_reversion( ) -> Tuple[FQ, FQ, FQ]: row = self.state_write_with_reversion( RWTableTag.AccountStorage, - [account_address, storage_key, Tables._, Tables._, Tables._, tx_id], + [account_address, storage_key, 0, Tables._, Tables._, tx_id], is_persistent, rw_counter_end_of_reversion, state_write_counter,