ethereum.forks.amsterdam.vm.instructions.storage

Ethereum Virtual Machine (EVM) Storage Instructions.

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Implementations of the EVM storage related instructions.

sload

Loads to the stack, the value corresponding to a certain key from the storage of the current account.

Parameters

evm : The current EVM frame.

def sload(evm: Evm) -> None:
38
    <snip>
48
    # STACK
49
    key = pop(evm.stack).to_be_bytes32()
50
51
    # GAS
52
    if (evm.message.current_target, key) in evm.accessed_storage_keys:
53
        charge_gas(evm, GasCosts.WARM_ACCESS)
54
    else:
55
        evm.accessed_storage_keys.add((evm.message.current_target, key))
56
        charge_gas(evm, GasCosts.COLD_STORAGE_ACCESS)
57
58
    # OPERATION
59
    tx_state = evm.message.tx_env.state
60
    value = get_storage(tx_state, evm.message.current_target, key)
61
62
    push(evm.stack, value)
63
64
    # PROGRAM COUNTER
65
    evm.pc += Uint(1)

sstore

Stores a value at a certain key in the current context's storage.

Parameters

evm : The current EVM frame.

def sstore(evm: Evm) -> None:
69
    <snip>
78
    if evm.message.is_static:
79
        raise WriteInStaticContext
80
81
    # STACK
82
    key = pop(evm.stack).to_be_bytes32()
83
    new_value = pop(evm.stack)
84
85
    # GAS (STATE-INDEPENDENT)
86
    # Price what is computable without touching state, and check it is
87
    # affordable before any state access is performed.
88
    gas_cost = Uint(0)
89
90
    # Access cost: cold or warm, always charged.
91
    is_cold_access = (
92
        evm.message.current_target,
93
        key,
94
    ) not in evm.accessed_storage_keys
95
    if is_cold_access:
96
        gas_cost += GasCosts.COLD_STORAGE_ACCESS
97
    else:
98
        gas_cost += GasCosts.WARM_ACCESS
99
100
    # Gas must cover the access cost before the state access below
101
    # records the slot read in the Block Access List. Post-repricing the
102
    # access cost can exceed the stipend, so the EIP-2200 stipend sentry
103
    # (`gas_left > CALL_STIPEND`) is no longer sufficient on its own.
104
    check_gas(evm, max(gas_cost, GasCosts.CALL_STIPEND + Uint(1)))
105
106
    # STATE ACCESS (STATE-DEPENDENT GAS)
107
    # Perform the access and complete the state-dependent pricing from
108
    # the slot's original and current values, adjusting the
109
    # transaction's refunds.
110
    if is_cold_access:
111
        evm.accessed_storage_keys.add((evm.message.current_target, key))
112
113
    tx_state = evm.message.tx_env.state
114
    original_value = get_storage_original(
115
        tx_state, evm.message.current_target, key
116
    )
117
    current_value = get_storage(tx_state, evm.message.current_target, key)
118
119
    state_gas = StateGas(Uint(0))
120
121
    # Write cost: charged on the first change to the slot this transaction.
122
    if original_value == current_value and current_value != new_value:
123
        gas_cost += GasCosts.STORAGE_WRITE
124
125
    # Refund Counter Calculation
126
    if current_value != new_value:
127
        if original_value != 0 and current_value != 0 and new_value == 0:
128
            # Storage is cleared for the first time in the transaction
129
            evm.gas_meter.refund_counter += GasCosts.REFUND_STORAGE_CLEAR
130
131
        if original_value != 0 and current_value == 0:
132
            # Gas refund issued earlier to be reversed
133
            evm.gas_meter.refund_counter -= GasCosts.REFUND_STORAGE_CLEAR
134
135
        if original_value == new_value:
136
            # Slot restored to its original value: refund the STORAGE_WRITE
137
            # charged on the first-time change earlier this transaction.
138
            evm.gas_meter.refund_counter += int(GasCosts.STORAGE_WRITE)
139
140
    # STATE GAS
141
    # A first-time set of a zero slot pays for the state it creates; a
142
    # slot set then cleared refills the earlier charge.
143
    if original_value == current_value and current_value != new_value:
144
        if original_value == 0:
145
            state_gas = StateGasCosts.STORAGE_SET
146
147
    if current_value != new_value and original_value == new_value:
148
        if original_value == 0:
149
            # Slot set then cleared: refund the state gas charge.
150
            credit_state_gas_refund(evm.gas_meter, StateGasCosts.STORAGE_SET)
151
152
    # Charge regular gas before state gas so that a regular-gas OOG
153
    # does not consume state gas that would inflate the parent's
154
    # reservoir on frame failure.
155
    charge_gas(evm, gas_cost)
156
    charge_state_gas(evm, state_gas)
157
    set_storage(tx_state, evm.message.current_target, key, new_value)
158
159
    # PROGRAM COUNTER
160
    evm.pc += Uint(1)

tload

Loads to the stack, the value corresponding to a certain key from the transient storage of the current account.

Parameters

evm : The current EVM frame.

def tload(evm: Evm) -> None:
164
    <snip>
174
    # STACK
175
    key = pop(evm.stack).to_be_bytes32()
176
177
    # GAS
178
    charge_gas(evm, GasCosts.OPCODE_TLOAD)
179
180
    # OPERATION
181
    value = get_transient_storage(
182
        evm.message.tx_env.state, evm.message.current_target, key
183
    )
184
    push(evm.stack, value)
185
186
    # PROGRAM COUNTER
187
    evm.pc += Uint(1)

tstore

Stores a value at a certain key in the current context's transient storage.

Parameters

evm : The current EVM frame.

def tstore(evm: Evm) -> None:
191
    <snip>
200
    if evm.message.is_static:
201
        raise WriteInStaticContext
202
203
    # STACK
204
    key = pop(evm.stack).to_be_bytes32()
205
    new_value = pop(evm.stack)
206
207
    # GAS
208
    charge_gas(evm, GasCosts.OPCODE_TSTORE)
209
    set_transient_storage(
210
        evm.message.tx_env.state,
211
        evm.message.current_target,
212
        key,
213
        new_value,
214
    )
215
216
    # PROGRAM COUNTER
217
    evm.pc += Uint(1)