Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
0b939b9
init: increase RwTable size
0xmountaintop Jan 14, 2022
74198e3
fix test except begin_tx
0xmountaintop Jan 17, 2022
ee16a51
fix test_ begin_tx
0xmountaintop Jan 17, 2022
a2dea64
clean up
0xmountaintop Jan 17, 2022
b69f88e
lint codes
0xmountaintop Jan 17, 2022
c110cb1
fix call_context_lookup
0xmountaintop Jan 17, 2022
d7d3557
fix stack_lookup
0xmountaintop Jan 17, 2022
d1dd796
Merge branch 'appliedzkp:master' into rw_table/add_aux
0xmountaintop Jan 17, 2022
3d1fb68
Merge remote-tracking branch 'origin/master' into rw_table/add_aux
0xmountaintop Jan 17, 2022
fc3bf79
update
0xmountaintop Jan 17, 2022
fb84b49
Merge branch 'rw_table/add_aux' of github.com:scroll-tech/zkevm-specs…
0xmountaintop Jan 17, 2022
7d3083f
merge
0xmountaintop Jan 20, 2022
a4b4267
fix
0xmountaintop Jan 20, 2022
2118d2f
Merge branch 'master' into rw_table/add_aux
0xmountaintop Jan 22, 2022
47b195b
fix
0xmountaintop Jan 24, 2022
1b0a6f1
update
0xmountaintop Jan 24, 2022
cbf96cb
fix test_sload
0xmountaintop Jan 24, 2022
77208d0
t# This is a combination of 2 commits.
0xmountaintop Jan 24, 2022
72e099d
rename
0xmountaintop Jan 25, 2022
ffe446e
merge
0xmountaintop Jan 26, 2022
807f607
format .md
0xmountaintop Jan 26, 2022
49bc579
fix
0xmountaintop Jan 26, 2022
d8b9400
better naming
0xmountaintop Jan 26, 2022
ce751bf
merge
0xmountaintop Jan 27, 2022
7b2ef54
fix
0xmountaintop Jan 27, 2022
c74effd
update markdown
0xmountaintop Jan 27, 2022
2537366
update python
0xmountaintop Jan 27, 2022
a01a2d0
update markdown
0xmountaintop Feb 10, 2022
026ac28
update sload codes
0xmountaintop Feb 10, 2022
c7e504e
update test_sload
0xmountaintop Feb 10, 2022
ab5fc3c
update test_sstore
0xmountaintop Feb 10, 2022
cf2e843
Merge remote-tracking branch 'origin/master' into new_sload_sstore
0xmountaintop Feb 10, 2022
5a284c0
change lookup for CalleeAddress from TxContextLookup to CallContextLo…
0xmountaintop Feb 11, 2022
181e3e6
Update tx refund (#36)
0xmountaintop Feb 13, 2022
715a3ba
format codes
0xmountaintop Feb 13, 2022
0cf9a92
improve
0xmountaintop Feb 15, 2022
c5e07c7
Merge remote-tracking branch 'upstream/master' into new_sload_sstore
silathdiir Feb 16, 2022
58028bc
Fix to FQ (from int) as PR-109.
silathdiir Feb 16, 2022
b2f9c41
Merge branch 'master' into new_sload_sstore
0xmountaintop Feb 17, 2022
fabec71
Fix to return FQ for some functions in `instruction.py`, and run `mak…
silathdiir Feb 17, 2022
43c4033
merge with master and fix conflicts
0xmountaintop Feb 18, 2022
49cc2e7
remove "intrinsic gas" comments
0xmountaintop Feb 18, 2022
7976899
update account_storage_read, use tx_id, enforce following stak_push
0xmountaintop Feb 18, 2022
1342c12
fix test_sload
0xmountaintop Feb 18, 2022
e889c47
move storage_gas to param.py
0xmountaintop Feb 18, 2022
066a743
fix
0xmountaintop Feb 18, 2022
2b7e16e
update account_storage_write_with_reversion, use tx_id, constrain val…
0xmountaintop Feb 18, 2022
7459dd3
fix
0xmountaintop Feb 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions specs/opcode/54SLOAD_55SSTORE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# 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`: +8
- 4 call_context read
- 2 stack operations
- 1 storage reads
- 1 access_list write
- `SSTORE`: +9
- 4 call_context read
- 2 stack operations
- 1 storage reads/writes
- 1 access_list write
- 1 gas_refund 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 `key` is warm: gas + WARM_STORAGE_READ_COST
- the accessed `key` is cold: gas + COLD_SLOAD_COST
- `SSTORE`:
- 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 `key` 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`: 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`: 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.
- `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
- storage:
- 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

## 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).
6 changes: 5 additions & 1 deletion src/zkevm_specs/evm/execution/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
from .callvalue import *
from .calldatacopy import *
from .gas import *
from .gasprice import *
from .jump import *
from .jumpi import *
from .push import *
from .slt_sgt import *
from .gas import *
from .gasprice import *
from .storage import *
from .selfbalance import *


Expand All @@ -41,6 +43,8 @@
ExecutionState.PUSH: push,
ExecutionState.SCMP: scmp,
ExecutionState.GAS: gas,
ExecutionState.SLOAD: sload,
ExecutionState.SSTORE: sstore,
ExecutionState.SELFBALANCE: selfbalance,
ExecutionState.GASPRICE: gasprice,
}
111 changes: 111 additions & 0 deletions src/zkevm_specs/evm/execution/storage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from ..instruction import Instruction, Transition
from ..opcode import Opcode
from ..table import CallContextFieldTag, TxContextFieldTag
from ...util.param 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.call_context_lookup(CallContextFieldTag.CalleeAddress)

storage_key = instruction.stack_pop()

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
)

dynamic_gas_cost = WARM_STORAGE_READ_COST if is_warm == 1 else COLD_SLOAD_COST

instruction.step_state_transition_in_same_context(
opcode,
rw_counter=Transition.delta(8),
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.call_context_lookup(CallContextFieldTag.CalleeAddress)

storage_key = instruction.stack_pop()
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(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
)

gas_refund, gas_refund_prev = instruction.tx_refund_write_with_reversion(
tx_id, is_persistent, rw_counter_end_of_reversion
)
gas_refund_new = gas_refund_prev
if value_prev != value:
if original_value == value_prev:
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 == 0:
gas_refund_new = gas_refund_new + SSTORE_CLEARS_SCHEDULE
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:
dynamic_gas_cost = SLOAD_GAS
else:
if original_value == value_prev:
if original_value == 0:
dynamic_gas_cost = SSTORE_SET_GAS
else:
dynamic_gas_cost = SSTORE_RESET_GAS
else:
dynamic_gas_cost = SLOAD_GAS
if is_warm == 0:
dynamic_gas_cost = dynamic_gas_cost + COLD_SLOAD_COST

instruction.step_state_transition_in_same_context(
opcode,
rw_counter=Transition.delta(9),
program_counter=Transition.delta(1),
stack_pointer=Transition.delta(2),
state_write_counter=Transition.delta(3),
dynamic_gas_cost=dynamic_gas_cost,
)
54 changes: 48 additions & 6 deletions src/zkevm_specs/evm/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def state_write_with_reversion(

def call_context_lookup(
self, field_tag: CallContextFieldTag, rw: RW = RW.Read, call_id: Optional[int] = None
) -> Union[FQ, RLC]:
) -> FQ:
if call_id is None:
call_id = self.curr.call_id
return self.rw_lookup(rw, RWTableTag.CallContext, [call_id, field_tag])[-4]
Expand Down Expand Up @@ -440,6 +440,22 @@ def tx_refund_read(self, tx_id) -> FQ:
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[FQ, FQ]:
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) -> FQ:
row = self.rw_lookup(RW.Read, RWTableTag.Account, [account_address, account_field_tag])
return row[-4]
Expand Down Expand Up @@ -527,6 +543,32 @@ def sub_balance_with_reversion(
self.constrain_zero(carry)
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],
)
return row[-4]

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]:
row = self.state_write_with_reversion(
RWTableTag.AccountStorage,
[account_address, storage_key, 0, Tables._, Tables._, tx_id],
is_persistent,
rw_counter_end_of_reversion,
state_write_counter,
)
return row[-4], row[-3], row[-1]

def add_account_to_access_list(
self,
tx_id: int,
Expand Down Expand Up @@ -561,13 +603,13 @@ def add_account_storage_to_access_list(
tx_id: int,
account_address: int,
storage_key: int,
) -> bool:
) -> Tuple[FQ, FQ]:
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,
Expand All @@ -577,15 +619,15 @@ 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[FQ, FQ]:
row = self.state_write_with_reversion(
RWTableTag.TxAccessListAccountStorage,
[tx_id, account_address, storage_key, 1],
is_persistent,
rw_counter_end_of_reversion,
state_write_counter,
)
return row[-4] - row[-3]
return row[-4], row[-3]

def transfer_with_gas_fee(
self,
Expand Down Expand Up @@ -618,7 +660,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],
Expand Down
8 changes: 8 additions & 0 deletions src/zkevm_specs/util/param.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading