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) |