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
    <snip>
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
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
    <snip>
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)
76
    if evm.gas_left <= GasCosts.CALL_STIPEND:
77
        raise OutOfGasError
83
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
    )
91
    current_value = get_storage(tx_state, evm.message.current_target, key)
92
93
    gas_cost = Uint(0)
94
    state_gas = StateGas(Uint(0))
95
87
    if (evm.message.current_target, key) not in evm.accessed_storage_keys:
96
    # Access cost: cold or warm, always charged.
97
    if (evm.message.current_target, key) not in evm.accessed_storage_keys:
98
        evm.accessed_storage_keys.add((evm.message.current_target, key))
89
        gas_cost += GasCosts.COLD_STORAGE_ACCESS
90
91
    if original_value == current_value and current_value != new_value:
92
        if original_value == 0:
93
            gas_cost += GasCosts.STORAGE_SET
94
        else:
95
            gas_cost += (
96
                GasCosts.COLD_STORAGE_WRITE - GasCosts.COLD_STORAGE_ACCESS
97
            )
99
        gas_cost += GasCosts.COLD_STORAGE_ACCESS
100
    else:
101
        gas_cost += GasCosts.WARM_ACCESS
102
103
    # Write cost: charged on the first change to the slot this transaction.
104
    if original_value == current_value and current_value != new_value:
105
        gas_cost += GasCosts.STORAGE_WRITE
106
107
    # Refund Counter Calculation
108
    if current_value != new_value:
109
        if original_value != 0 and current_value != 0 and new_value == 0:
110
            # Storage is cleared for the first time in the transaction
111
            evm.refund_counter += GasCosts.REFUND_STORAGE_CLEAR
112
113
        if original_value != 0 and current_value == 0:
114
            # Gas refund issued earlier to be reversed
115
            evm.refund_counter -= GasCosts.REFUND_STORAGE_CLEAR
116
117
        if original_value == new_value:
112
            # Storage slot being restored to its original value
113
            if original_value == 0:
114
                # Slot was originally empty and was SET earlier
115
                evm.refund_counter += int(
116
                    GasCosts.STORAGE_SET - GasCosts.WARM_ACCESS
117
                )
118
            else:
119
                # Slot was originally non-empty and was UPDATED earlier
120
                evm.refund_counter += int(
121
                    GasCosts.COLD_STORAGE_WRITE
122
                    - GasCosts.COLD_STORAGE_ACCESS
123
                    - GasCosts.WARM_ACCESS
124
                )
118
            # Slot restored to its original value: refund the STORAGE_WRITE
119
            # charged on the first-time change earlier this transaction.
120
            evm.refund_counter += int(GasCosts.STORAGE_WRITE)
121
126
    charge_gas(evm, gas_cost)
127
    if evm.message.is_static:
128
        raise WriteInStaticContext
122
    if original_value == current_value and current_value != new_value:
123
        if original_value == 0:
124
            state_gas = StateGasCosts.STORAGE_SET
125
126
    if current_value != new_value and original_value == new_value:
127
        if original_value == 0:
128
            # Slot set then cleared: refund the state gas charge.
129
            credit_state_gas_refund(evm, StateGasCosts.STORAGE_SET)
130
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
    charge_state_gas(evm, state_gas)
136
    set_storage(tx_state, evm.message.current_target, key, new_value)
137
138
    # PROGRAM COUNTER
139
    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:
143
    <snip>
153
    # STACK
154
    key = pop(evm.stack).to_be_bytes32()
155
156
    # GAS
150
    charge_gas(evm, GasCosts.WARM_ACCESS)
157
    charge_gas(evm, GasCosts.OPCODE_TLOAD)
158
159
    # OPERATION
160
    value = get_transient_storage(
161
        evm.message.tx_env.state, evm.message.current_target, key
162
    )
163
    push(evm.stack, value)
164
165
    # PROGRAM COUNTER
166
    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:
170
    <snip>
179
    if evm.message.is_static:
180
        raise WriteInStaticContext
181
182
    # STACK
183
    key = pop(evm.stack).to_be_bytes32()
184
    new_value = pop(evm.stack)
185
186
    # GAS
177
    charge_gas(evm, GasCosts.WARM_ACCESS)
178
    if evm.message.is_static:
179
        raise WriteInStaticContext
187
    charge_gas(evm, GasCosts.OPCODE_TSTORE)
188
    set_transient_storage(
189
        evm.message.tx_env.state,
190
        evm.message.current_target,
191
        key,
192
        new_value,
193
    )
194
195
    # PROGRAM COUNTER
196
    evm.pc += Uint(1)