ethereum.forks.bpo5.vm.instructions.storageethereum.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:
37
    """
38
    Loads to the stack, the value corresponding to a certain key from the
39
    storage of the current account.
40
41
    Parameters
42
    ----------
43
    evm :
44
        The current EVM frame.
45
46
    """
47
    # STACK
48
    key = pop(evm.stack).to_be_bytes32()
49
50
    # GAS
51
    if (evm.message.current_target, key) in evm.accessed_storage_keys:
52
        charge_gas(evm, GasCosts.WARM_ACCESS)
53
    else:
54
        evm.accessed_storage_keys.add((evm.message.current_target, key))
55
        charge_gas(evm, GasCosts.COLD_STORAGE_ACCESS)
56
57
    # OPERATION
54
    value = get_storage(
55
        evm.message.block_env.state, evm.message.current_target, key
56
    )
58
    tx_state = evm.message.tx_env.state
59
    value = get_storage(tx_state, evm.message.current_target, key)
60
61
    push(evm.stack, value)
62
63
    # PROGRAM COUNTER
64
    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:
68
    """
69
    Stores a value at a certain key in the current context's storage.
70
71
    Parameters
72
    ----------
73
    evm :
74
        The current EVM frame.
75
76
    """
77
    if evm.message.is_static:
78
        raise WriteInStaticContext
79
80
    # STACK
81
    key = pop(evm.stack).to_be_bytes32()
82
    new_value = pop(evm.stack)
77
    if evm.gas_left <= GasCosts.CALL_STIPEND:
78
        raise OutOfGasError
83
80
    state = evm.message.block_env.state
81
    original_value = get_storage_original(
82
        state, evm.message.current_target, key
84
    # check we have at least the stipend gas
85
    check_gas(evm, GasCosts.CALL_STIPEND + Uint(1))
86
87
    tx_state = evm.message.tx_env.state
88
    original_value = get_storage_original(
89
        tx_state, evm.message.current_target, key
90
    )
84
    current_value = get_storage(state, evm.message.current_target, key)
91
    current_value = get_storage(tx_state, evm.message.current_target, key)
92
93
    state_gas_storage_set = STATE_BYTES_PER_STORAGE_SET * COST_PER_STATE_BYTE
94
    gas_cost = Uint(0)
95
96
    if (evm.message.current_target, key) not in evm.accessed_storage_keys:
97
        evm.accessed_storage_keys.add((evm.message.current_target, key))
98
        gas_cost += GasCosts.COLD_STORAGE_ACCESS
99
100
    needs_state_gas = False
101
    if original_value == current_value and current_value != new_value:
102
        if original_value == 0:
94
            gas_cost += GasCosts.STORAGE_SET
95
        else:
96
            gas_cost += (
97
                GasCosts.COLD_STORAGE_WRITE - GasCosts.COLD_STORAGE_ACCESS
98
            )
103
            needs_state_gas = True
104
        # charge regular cost for the operation, even when we
105
        # already charge state gas for state creation
106
        gas_cost += GasCosts.COLD_STORAGE_WRITE - GasCosts.COLD_STORAGE_ACCESS
107
    else:
108
        gas_cost += GasCosts.WARM_ACCESS
109
110
    # Refund Counter Calculation
111
    if current_value != new_value:
112
        if original_value != 0 and current_value != 0 and new_value == 0:
113
            # Storage is cleared for the first time in the transaction
114
            evm.refund_counter += GasCosts.REFUND_STORAGE_CLEAR
115
116
        if original_value != 0 and current_value == 0:
117
            # Gas refund issued earlier to be reversed
118
            evm.refund_counter -= GasCosts.REFUND_STORAGE_CLEAR
119
120
        if original_value == new_value:
121
            # Storage slot being restored to its original value
122
            if original_value == 0:
115
                # Slot was originally empty and was SET earlier
116
                evm.refund_counter += int(
117
                    GasCosts.STORAGE_SET - GasCosts.WARM_ACCESS
118
                )
119
            else:
120
                # Slot was originally non-empty and was UPDATED earlier
121
                evm.refund_counter += int(
122
                    GasCosts.COLD_STORAGE_WRITE
123
                    - GasCosts.COLD_STORAGE_ACCESS
124
                    - GasCosts.WARM_ACCESS
125
                )
123
                # Slot set then cleared: refund the state gas charge.
124
                credit_state_gas_refund(evm, state_gas_storage_set)
125
            evm.refund_counter += int(
126
                GasCosts.COLD_STORAGE_WRITE
127
                - GasCosts.COLD_STORAGE_ACCESS
128
                - GasCosts.WARM_ACCESS
129
            )
130
127
    charge_gas(evm, gas_cost)
128
    if evm.message.is_static:
129
        raise WriteInStaticContext
130
    set_storage(state, evm.message.current_target, key, new_value)
131
    # Charge regular gas before state gas so that a regular-gas OOG
132
    # does not consume state gas that would inflate the parent's
133
    # reservoir on frame failure.
134
    charge_gas(evm, gas_cost)
135
    if needs_state_gas:
136
        charge_state_gas(evm, state_gas_storage_set)
137
    set_storage(tx_state, evm.message.current_target, key, new_value)
138
139
    # PROGRAM COUNTER
140
    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:
144
    """
145
    Loads to the stack, the value corresponding to a certain key from the
146
    transient storage of the current account.
147
148
    Parameters
149
    ----------
150
    evm :
151
        The current EVM frame.
152
153
    """
154
    # STACK
155
    key = pop(evm.stack).to_be_bytes32()
156
157
    # GAS
158
    charge_gas(evm, GasCosts.WARM_ACCESS)
159
160
    # OPERATION
154
    value = get_transient_storage(
155
        evm.message.tx_env.transient_storage, evm.message.current_target, key
161
    value = get_transient_storage(
162
        evm.message.tx_env.state, evm.message.current_target, key
163
    )
164
    push(evm.stack, value)
165
166
    # PROGRAM COUNTER
167
    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:
171
    """
172
    Stores a value at a certain key in the current context's transient storage.
173
174
    Parameters
175
    ----------
176
    evm :
177
        The current EVM frame.
178
179
    """
180
    if evm.message.is_static:
181
        raise WriteInStaticContext
182
183
    # STACK
184
    key = pop(evm.stack).to_be_bytes32()
185
    new_value = pop(evm.stack)
186
187
    # GAS
188
    charge_gas(evm, GasCosts.WARM_ACCESS)
179
    if evm.message.is_static:
180
        raise WriteInStaticContext
181
    set_transient_storage(
182
        evm.message.tx_env.transient_storage,
189
    set_transient_storage(
190
        evm.message.tx_env.state,
191
        evm.message.current_target,
192
        key,
193
        new_value,
194
    )
195
196
    # PROGRAM COUNTER
197
    evm.pc += Uint(1)