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]

storage_clears

Addresses whose pre-existing storage was wiped during block execution (via a pre-EIP-6780 SELFDESTRUCT). Their storage tries are dropped before storage_changes is applied, so any post-wipe writes begin from empty storage.

74
    storage_clears: Set[Address] = field(default_factory=set)

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]:
94
        <snip>
99
        ...

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:
102
        <snip>
107
        ...

get_code

Get the bytecode for a given code hash.

Return b"" for EMPTY_CODE_HASH.

def get_code(self, ​​code_hash: Hash32) -> Bytes:
110
        <snip>
115
        ...

account_has_storage

Check whether an account has any storage.

Only needed for EIP-7610.

def account_has_storage(self, ​​address: Address) -> bool:
118
        <snip>
123
        ...

compute_state_root_and_trie_changes

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

storage_clears lists addresses whose pre-existing storage tries must be dropped before storage_changes is applied, so any post-wipe writes begin from empty storage.

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]], ​​storage_clears: AbstractSet[Address]) -> Tuple[Root, List["InternalNode"]]:
131
        <snip>
141
        ...

State

Contains all information that is preserved between transactions.

144
@dataclass
class State:

_main_trie

150
    _main_trie: Trie[Address, Optional[Account]] = field(
151
        default_factory=lambda: Trie(secured=True, default=None)
152
    )

_storage_tries

153
    _storage_tries: Dict[Address, Trie[Bytes32, U256]] = field(
154
        default_factory=dict
155
    )

_code_store

156
    _code_store: Dict[Hash32, Bytes] = field(
157
        default_factory=dict, compare=False
158
    )

get_code

Get the bytecode for a given code hash.

Return b"" for EMPTY_CODE_HASH.

def get_code(self, ​​code_hash: Hash32) -> Bytes:
161
        <snip>
166
        if code_hash == EMPTY_CODE_HASH:
167
            return b""
168
        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]:
171
        <snip>
176
        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:
179
        <snip>
184
        trie = self._storage_tries.get(address)
185
        if trie is None:
186
            return U256(0)
187
188
        value = trie_get(trie, key)
189
190
        assert isinstance(value, U256)
191
        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:
194
        <snip>
199
        return address in self._storage_tries

compute_state_root_and_trie_changes

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

storage_clears lists addresses whose pre-existing storage tries are dropped before storage_changes is applied, so any post-wipe writes begin from empty storage.

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]], ​​storage_clears: AbstractSet[Address]) -> Tuple[Root, List["InternalNode"]]:
207
        <snip>
217
        main_trie = copy_trie(self._main_trie)
218
        storage_tries = {
219
            k: copy_trie(v)
220
            for k, v in self._storage_tries.items()
221
            if k not in storage_clears
222
        }
223
224
        for address, account in account_changes.items():
225
            trie_set(main_trie, address, account)
226
227
        for address, slots in storage_changes.items():
228
            trie = storage_tries.get(address)
229
            if trie is None:
230
                trie = Trie(secured=True, default=U256(0))
231
                storage_tries[address] = trie
232
            for key, value in slots.items():
233
                trie_set(trie, key, value)
234
            if trie._data == {}:
235
                del storage_tries[address]
236
237
        def get_storage_root(addr: Address) -> Root:
238
            if addr in storage_tries:
239
                return root(storage_tries[addr])
240
            return EMPTY_TRIE_ROOT
241
242
        state_root_value = root(main_trie, get_storage_root=get_storage_root)
243
244
        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:
248
    <snip>
252
    del state._main_trie
253
    del state._storage_tries
254
    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:
258
    <snip>
269
    for address in diff.storage_clears:
270
        state._storage_tries.pop(address, None)
271
272
    for address, account in diff.account_changes.items():
273
        trie_set(state._main_trie, address, account)
274
275
    for address, slots in diff.storage_changes.items():
276
        trie = state._storage_tries.get(address)
277
        if trie is None:
278
            trie = Trie(secured=True, default=U256(0))
279
            state._storage_tries[address] = trie
280
        for key, value in slots.items():
281
            trie_set(trie, key, value)
282
        if trie._data == {}:
283
            del state._storage_tries[address]
284
285
    state._code_store.update(diff.code_changes)

store_code

Store bytecode in State.

def store_code(state: State, ​​code: Bytes) -> Hash32:
289
    <snip>
292
    code_hash = keccak256(code)
293
    if code_hash != EMPTY_CODE_HASH:
294
        state._code_store[code_hash] = code
295
    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:
303
    <snip>
308
    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:
317
    <snip>
322
    assert trie_get(state._main_trie, address) is not None
323
324
    trie = state._storage_tries.get(address)
325
    if trie is None:
326
        trie = Trie(secured=True, default=U256(0))
327
        state._storage_tries[address] = trie
328
    trie_set(trie, key, value)
329
    if trie._data == {}:
330
        del state._storage_tries[address]

state_root

Compute the state root of the current state.

def state_root(state: State) -> Root:
334
    <snip>
337
    root_value, _ = state.compute_state_root_and_trie_changes({}, {})
338
    return root_value