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:
39
    """
40
    Loads to the stack, the value corresponding to a certain key from the
41
    storage of the current account.
42
43
    Parameters
44
    ----------
45
    evm :
46
        The current EVM frame.
47
48
    """
49
    # STACK
50
    key = pop(evm.stack).to_be_bytes32()
51
52
    # GAS
53
    if (evm.message.current_target, key) in evm.accessed_storage_keys:
54
        charge_gas(evm, GAS_WARM_ACCESS)
55
    else:
56
        evm.accessed_storage_keys.add((evm.message.current_target, key))
57
        charge_gas(evm, GAS_COLD_STORAGE_ACCESS)
58
59
    # OPERATION
59
    value = get_storage(
60
        evm.message.block_env.state, evm.message.current_target, key
61
    )
60
    tx_state = evm.message.tx_env.state
61
    value = get_storage(tx_state, evm.message.current_target, key)
62
63
    push(evm.stack, value)
64
65
    # PROGRAM COUNTER
66
    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:
70
    """
71
    Stores a value at a certain key in the current context's storage.
72
73
    Parameters
74
    ----------
75
    evm :
76
        The current EVM frame.
77
78
    """
79
    if evm.message.is_static:
80
        raise WriteInStaticContext
81
82
    # STACK
83
    key = pop(evm.stack).to_be_bytes32()
84
    new_value = pop(evm.stack)
82
    if evm.gas_left <= GAS_CALL_STIPEND:
83
        raise OutOfGasError
85
85
    state = evm.message.block_env.state
86
    original_value = get_storage_original(
87
        state, evm.message.current_target, key
86
    # check we have at least the stipend gas
87
    check_gas(evm, GAS_CALL_STIPEND + Uint(1))
88
89
    tx_state = evm.message.tx_env.state
90
    original_value = get_storage_original(
91
        tx_state, evm.message.current_target, key
92
    )
89
    current_value = get_storage(state, evm.message.current_target, key)
93
    current_value = get_storage(tx_state, evm.message.current_target, key)
94
95
    gas_cost = Uint(0)
96
97
    if (evm.message.current_target, key) not in evm.accessed_storage_keys:
98
        evm.accessed_storage_keys.add((evm.message.current_target, key))
99
        gas_cost += GAS_COLD_STORAGE_ACCESS
100
101
    if original_value == current_value and current_value != new_value:
102
        if original_value == 0:
103
            gas_cost += GAS_STORAGE_SET
104
        else:
105
            gas_cost += GAS_COLD_STORAGE_WRITE - GAS_COLD_STORAGE_ACCESS
106
    else:
107
        gas_cost += GAS_WARM_ACCESS
108
109
    # Refund Counter Calculation
110
    if current_value != new_value:
111
        if original_value != 0 and current_value != 0 and new_value == 0:
112
            # Storage is cleared for the first time in the transaction
113
            evm.refund_counter += REFUND_STORAGE_CLEAR
114
115
        if original_value != 0 and current_value == 0:
116
            # Gas refund issued earlier to be reversed
117
            evm.refund_counter -= REFUND_STORAGE_CLEAR
118
119
        if original_value == new_value:
120
            # Storage slot being restored to its original value
121
            if original_value == 0:
122
                # Slot was originally empty and was SET earlier
123
                evm.refund_counter += int(GAS_STORAGE_SET - GAS_WARM_ACCESS)
124
            else:
125
                # Slot was originally non-empty and was UPDATED earlier
126
                evm.refund_counter += int(
127
                    GAS_COLD_STORAGE_WRITE
128
                    - GAS_COLD_STORAGE_ACCESS
129
                    - GAS_WARM_ACCESS
130
                )
131
132
    charge_gas(evm, gas_cost)
129
    if evm.message.is_static:
130
        raise WriteInStaticContext
131
    set_storage(state, evm.message.current_target, key, new_value)
133
    set_storage(tx_state, evm.message.current_target, key, new_value)
134
135
    # PROGRAM COUNTER
136
    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:
140
    """
141
    Loads to the stack, the value corresponding to a certain key from the
142
    transient storage of the current account.
143
144
    Parameters
145
    ----------
146
    evm :
147
        The current EVM frame.
148
149
    """
150
    # STACK
151
    key = pop(evm.stack).to_be_bytes32()
152
153
    # GAS
154
    charge_gas(evm, GAS_WARM_ACCESS)
155
156
    # OPERATION
155
    value = get_transient_storage(
156
        evm.message.tx_env.transient_storage, evm.message.current_target, key
157
    value = get_transient_storage(
158
        evm.message.tx_env.state, evm.message.current_target, key
159
    )
160
    push(evm.stack, value)
161
162
    # PROGRAM COUNTER
163
    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:
167
    """
168
    Stores a value at a certain key in the current context's transient storage.
169
170
    Parameters
171
    ----------
172
    evm :
173
        The current EVM frame.
174
175
    """
176
    if evm.message.is_static:
177
        raise WriteInStaticContext
178
179
    # STACK
180
    key = pop(evm.stack).to_be_bytes32()
181
    new_value = pop(evm.stack)
182
183
    # GAS
184
    charge_gas(evm, GAS_WARM_ACCESS)
180
    if evm.message.is_static:
181
        raise WriteInStaticContext
182
    set_transient_storage(
183
        evm.message.tx_env.transient_storage,
185
    set_transient_storage(
186
        evm.message.tx_env.state,
187
        evm.message.current_target,
188
        key,
189
        new_value,
190
    )
191
192
    # PROGRAM COUNTER
193
    evm.pc += Uint(1)