ethereum.state

Shared state types and the PreState protocol used by the state transition function.

The PreState protocol specifies the operations that any pre-execution state provider must support, allowing multiple backing implementations (in-memory dict, on-disk database, witness, etc.).

The State class is the in-memory implementation of PreState. It consists of a main account trie and storage tries for each contract.

There is a distinction between an account that does not exist and EMPTY_ACCOUNT.

Address

34
Address = Bytes20

Root

35
Root = Hash32

EMPTY_CODE_HASH

37
EMPTY_CODE_HASH = keccak256(b"")

Account

State associated with an address.

40
@slotted_freezable
41
@dataclass
class Account:

nonce

47
    nonce: Uint

balance

48
    balance: U256

code_hash

49
    code_hash: Hash32

EMPTY_ACCOUNT

52
EMPTY_ACCOUNT = Account(
53
    nonce=Uint(0),
54
    balance=U256(0),
55
    code_hash=EMPTY_CODE_HASH,
56
)

BlockDiff

State changes produced by executing a block.

59
@dataclass
class BlockDiff:

account_changes

Per-address account diffs produced by execution.

65
    account_changes: Dict[Address, Optional[Account]]

storage_changes

Per-address storage diffs produced by execution.

68
    storage_changes: Dict[Address, Dict[Bytes32, U256]]

code_changes

New bytecodes (keyed by code hash) introduced by execution.

71
    code_changes: Dict[Hash32, Bytes]

PreState

Protocol for providing pre-execution state.

Specify the operations that any pre-state provider (dict, database, witness, etc.) must support for the EELS state transition.

class PreState:

get_account_optional

Get the account at an address.

Return None if there is no account at the address.

def get_account_optional(self, ​​address: Address) -> Optional[Account]:
84
        """
85
        Get the account at an address.
86
87
        Return ``None`` if there is no account at the address.
88
        """
89
        ...

get_storage

Get a storage value.

Return U256(0) if the key has not been set.

def get_storage(self, ​​address: Address, ​​key: Bytes32) -> U256:
92
        """
93
        Get a storage value.
94
95
        Return ``U256(0)`` if the key has not been set.
96
        """
97
        ...

get_code

Get the bytecode for a given code hash.

Return b"" for EMPTY_CODE_HASH.

def get_code(self, ​​code_hash: Hash32) -> Bytes:
100
        """
101
        Get the bytecode for a given code hash.
102
103
        Return ``b""`` for ``EMPTY_CODE_HASH``.
104
        """
105
        ...

account_has_storage

Check whether an account has any storage.

Only needed for EIP-7610.

def account_has_storage(self, ​​address: Address) -> bool:
108
        """
109
        Check whether an account has any storage.
110
111
        Only needed for EIP-7610.
112
        """
113
        ...

compute_state_root_and_trie_changes

Compute the state root after applying changes to the pre-state.

Return the new state root together with the internal trie nodes that were created or modified.

def compute_state_root_and_trie_changes(self, ​​account_changes: Dict[Address, Optional[Account]], ​​storage_changes: Dict[Address, Dict[Bytes32, U256]]) -> Tuple[Root, List["InternalNode"]]:
120
        """
121
        Compute the state root after applying changes to the pre-state.
122
123
        Return the new state root together with the internal trie nodes
124
        that were created or modified.
125
        """
126
        ...

State

Contains all information that is preserved between transactions.

129
@dataclass
class State:

_main_trie

135
    _main_trie: Trie[Address, Optional[Account]] = field(
136
        default_factory=lambda: Trie(secured=True, default=None)
137
    )

_storage_tries

138
    _storage_tries: Dict[Address, Trie[Bytes32, U256]] = field(
139
        default_factory=dict
140
    )

_code_store

141
    _code_store: Dict[Hash32, Bytes] = field(
142
        default_factory=dict, compare=False
143
    )

get_code

Get the bytecode for a given code hash.

Return b"" for EMPTY_CODE_HASH.

def get_code(self, ​​code_hash: Hash32) -> Bytes:
146
        """
147
        Get the bytecode for a given code hash.
148
149
        Return ``b""`` for ``EMPTY_CODE_HASH``.
150
        """
151
        if code_hash == EMPTY_CODE_HASH:
152
            return b""
153
        return self._code_store[code_hash]

get_account_optional

Get the account at an address.

Return None if there is no account at the address.

def get_account_optional(self, ​​address: Address) -> Optional[Account]:
156
        """
157
        Get the account at an address.
158
159
        Return ``None`` if there is no account at the address.
160
        """
161
        return trie_get(self._main_trie, address)

get_storage

Get a storage value.

Return U256(0) if the key has not been set.

def get_storage(self, ​​address: Address, ​​key: Bytes32) -> U256:
164
        """
165
        Get a storage value.
166
167
        Return ``U256(0)`` if the key has not been set.
168
        """
169
        trie = self._storage_tries.get(address)
170
        if trie is None:
171
            return U256(0)
172
173
        value = trie_get(trie, key)
174
175
        assert isinstance(value, U256)
176
        return value

account_has_storage

Check whether an account has any storage.

Only needed for EIP-7610.

def account_has_storage(self, ​​address: Address) -> bool:
179
        """
180
        Check whether an account has any storage.
181
182
        Only needed for EIP-7610.
183
        """
184
        return address in self._storage_tries

compute_state_root_and_trie_changes

Compute the state root after applying changes to the pre-state.

Return the new state root together with the internal trie nodes that were created or modified.

def compute_state_root_and_trie_changes(self, ​​account_changes: Dict[Address, Optional[Account]], ​​storage_changes: Dict[Address, Dict[Bytes32, U256]]) -> Tuple[Root, List["InternalNode"]]:
191
        """
192
        Compute the state root after applying changes to the pre-state.
193
194
        Return the new state root together with the internal trie nodes
195
        that were created or modified.
196
        """
197
        main_trie = copy_trie(self._main_trie)
198
        storage_tries = {
199
            k: copy_trie(v) for k, v in self._storage_tries.items()
200
        }
201
202
        for address, account in account_changes.items():
203
            trie_set(main_trie, address, account)
204
205
        for address, slots in storage_changes.items():
206
            trie = storage_tries.get(address)
207
            if trie is None:
208
                trie = Trie(secured=True, default=U256(0))
209
                storage_tries[address] = trie
210
            for key, value in slots.items():
211
                trie_set(trie, key, value)
212
            if trie._data == {}:
213
                del storage_tries[address]
214
215
        def get_storage_root(addr: Address) -> Root:
216
            if addr in storage_tries:
217
                return root(storage_tries[addr])
218
            return EMPTY_TRIE_ROOT
219
220
        state_root_value = root(main_trie, get_storage_root=get_storage_root)
221
222
        return state_root_value, []

close_state

Free resources held by the state. Used by optimized implementations to release file descriptors.

def close_state(state: State) -> None:
226
    """
227
    Free resources held by the state. Used by optimized implementations to
228
    release file descriptors.
229
    """
230
    del state._main_trie
231
    del state._storage_tries
232
    del state._code_store

apply_changes_to_state

Apply block-level diff to the State for the next block.

Parameters

state : The state to update. diff : Account, storage, and code changes to apply.

def apply_changes_to_state(state: State, ​​diff: BlockDiff) -> None:
236
    """
237
    Apply block-level diff to the ``State`` for the next block.
238
239
    Parameters
240
    ----------
241
    state :
242
        The state to update.
243
    diff :
244
        Account, storage, and code changes to apply.
245
246
    """
247
    for address, account in diff.account_changes.items():
248
        trie_set(state._main_trie, address, account)
249
250
    for address, slots in diff.storage_changes.items():
251
        trie = state._storage_tries.get(address)
252
        if trie is None:
253
            trie = Trie(secured=True, default=U256(0))
254
            state._storage_tries[address] = trie
255
        for key, value in slots.items():
256
            trie_set(trie, key, value)
257
        if trie._data == {}:
258
            del state._storage_tries[address]
259
260
    state._code_store.update(diff.code_changes)

store_code

Store bytecode in State.

def store_code(state: State, ​​code: Bytes) -> Hash32:
264
    """
265
    Store bytecode in ``State``.
266
    """
267
    code_hash = keccak256(code)
268
    if code_hash != EMPTY_CODE_HASH:
269
        state._code_store[code_hash] = code
270
    return code_hash

set_account

Set an account in a State.

Setting to None deletes the account.

def set_account(state: State, ​​address: Address, ​​account: Optional[Account]) -> None:
278
    """
279
    Set an account in a ``State``.
280
281
    Setting to ``None`` deletes the account.
282
    """
283
    trie_set(state._main_trie, address, account)

set_storage

Set a storage value in a State.

Setting to U256(0) deletes the key.

def set_storage(state: State, ​​address: Address, ​​key: Bytes32, ​​value: U256) -> None:
292
    """
293
    Set a storage value in a ``State``.
294
295
    Setting to ``U256(0)`` deletes the key.
296
    """
297
    assert trie_get(state._main_trie, address) is not None
298
299
    trie = state._storage_tries.get(address)
300
    if trie is None:
301
        trie = Trie(secured=True, default=U256(0))
302
        state._storage_tries[address] = trie
303
    trie_set(trie, key, value)
304
    if trie._data == {}:
305
        del state._storage_tries[address]

state_root

Compute the state root of the current state.

def state_root(state: State) -> Root:
309
    """
310
    Compute the state root of the current state.
311
    """
312
    root_value, _ = state.compute_state_root_and_trie_changes({}, {})
313
    return root_value