ethereum.berlin.vm.instructions.storageethereum.london.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:
32
    """
33
    Loads to the stack, the value corresponding to a certain key from the
34
    storage of the current account.
35
36
    Parameters
37
    ----------
38
    evm :
39
        The current EVM frame.
40
41
    """
42
    # STACK
43
    key = pop(evm.stack).to_be_bytes32()
44
45
    # GAS
46
    if (evm.message.current_target, key) in evm.accessed_storage_keys:
47
        charge_gas(evm, GAS_WARM_ACCESS)
48
    else:
49
        evm.accessed_storage_keys.add((evm.message.current_target, key))
50
        charge_gas(evm, GAS_COLD_SLOAD)
51
52
    # OPERATION
53
    value = get_storage(
54
        evm.message.block_env.state, evm.message.current_target, key
55
    )
56
57
    push(evm.stack, value)
58
59
    # PROGRAM COUNTER
60
    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:
64
    """
65
    Stores a value at a certain key in the current context's storage.
66
67
    Parameters
68
    ----------
69
    evm :
70
        The current EVM frame.
71
72
    """
73
    # STACK
74
    key = pop(evm.stack).to_be_bytes32()
75
    new_value = pop(evm.stack)
76
    if evm.gas_left <= GAS_CALL_STIPEND:
77
        raise OutOfGasError
78
79
    state = evm.message.block_env.state
80
    original_value = get_storage_original(
81
        state, evm.message.current_target, key
82
    )
83
    current_value = get_storage(state, evm.message.current_target, key)
84
85
    gas_cost = Uint(0)
86
87
    if (evm.message.current_target, key) not in evm.accessed_storage_keys:
88
        evm.accessed_storage_keys.add((evm.message.current_target, key))
89
        gas_cost += GAS_COLD_SLOAD
90
91
    if original_value == current_value and current_value != new_value:
92
        if original_value == 0:
93
            gas_cost += GAS_STORAGE_SET
94
        else:
95
            gas_cost += GAS_STORAGE_UPDATE - GAS_COLD_SLOAD
96
    else:
97
        gas_cost += GAS_WARM_ACCESS
98
99
    # Refund Counter Calculation
100
    if current_value != new_value:
101
        if original_value != 0 and current_value != 0 and new_value == 0:
102
            # Storage is cleared for the first time in the transaction
103
            evm.refund_counter += int(GAS_STORAGE_CLEAR_REFUND)
104
105
        if original_value != 0 and current_value == 0:
106
            # Gas refund issued earlier to be reversed
107
            evm.refund_counter -= int(GAS_STORAGE_CLEAR_REFUND)
108
109
        if original_value == new_value:
110
            # Storage slot being restored to its original value
111
            if original_value == 0:
112
                # Slot was originally empty and was SET earlier
113
                evm.refund_counter += int(GAS_STORAGE_SET - GAS_WARM_ACCESS)
114
            else:
115
                # Slot was originally non-empty and was UPDATED earlier
116
                evm.refund_counter += int(
117
                    GAS_STORAGE_UPDATE - GAS_COLD_SLOAD - GAS_WARM_ACCESS
118
                )
119
120
    charge_gas(evm, gas_cost)
121
    if evm.message.is_static:
122
        raise WriteInStaticContext
123
    set_storage(state, evm.message.current_target, key, new_value)
124
125
    # PROGRAM COUNTER
126
    evm.pc += Uint(1)