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

43
Address = Bytes20

Root

44
Root = Hash32

EMPTY_CODE_HASH

46
EMPTY_CODE_HASH = keccak256(b"")

Account

State associated with an address.

49
@final
50
@slotted_freezable
51
@dataclass
class Account:

nonce

57
    nonce: Uint

balance

58
    balance: U256

code_hash

59
    code_hash: Hash32

EMPTY_ACCOUNT

62
EMPTY_ACCOUNT = Account(
63
    nonce=Uint(0),
64
    balance=U256(0),
65
    code_hash=EMPTY_CODE_HASH,
66
)

BlockDiff

State changes produced by executing a block.

69
@final
70
@dataclass
class BlockDiff:

account_changes

Per-address account diffs produced by execution.

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

storage_changes

Per-address storage diffs produced by execution.

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

code_changes

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

82
    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.

85
    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]:
105
        <snip>
110
        ...

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:
113
        <snip>
118
        ...

get_code

Get the bytecode for a given code hash.

Return b"" for EMPTY_CODE_HASH.

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

account_has_storage

Check whether an account has any storage.

Only needed for EIP-7610.

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

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"]]:
142
        <snip>
152
        ...

State

Contains all information that is preserved between transactions.

155
@final
156
@dataclass
class State:

_main_trie

162
    _main_trie: Trie[Address, Optional[Account]] = field(
163
        default_factory=lambda: Trie(secured=True, default=None)
164
    )

_storage_tries

165
    _storage_tries: Dict[Address, Trie[Bytes32, U256]] = field(
166
        default_factory=dict
167
    )

_code_store

168
    _code_store: Dict[Hash32, Bytes] = field(
169
        default_factory=dict, compare=False
170
    )

get_code

Get the bytecode for a given code hash.

Return b"" for EMPTY_CODE_HASH.

def get_code(self, ​​code_hash: Hash32) -> Bytes:
173
        <snip>
178
        if code_hash == EMPTY_CODE_HASH:
179
            return b""
180
        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]:
183
        <snip>
188
        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:
191
        <snip>
196
        trie = self._storage_tries.get(address)
197
        if trie is None:
198
            return U256(0)
199
200
        value = trie_get(trie, key)
201
202
        assert isinstance(value, U256)
203
        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:
206
        <snip>
211
        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"]]:
219
        <snip>
229
        main_trie = copy_trie(self._main_trie)
230
        storage_tries = {
231
            k: copy_trie(v)
232
            for k, v in self._storage_tries.items()
233
            if k not in storage_clears
234
        }
235
236
        for address, account in account_changes.items():
237
            trie_set(main_trie, address, account)
238
239
        for address, slots in storage_changes.items():
240
            trie = storage_tries.get(address)
241
            if trie is None:
242
                trie = Trie(secured=True, default=U256(0))
243
                storage_tries[address] = trie
244
            for key, value in slots.items():
245
                trie_set(trie, key, value)
246
            if trie._data == {}:
247
                del storage_tries[address]
248
249
        def get_storage_root(addr: Address) -> Root:
250
            if addr in storage_tries:
251
                return root(storage_tries[addr])
252
            return EMPTY_TRIE_ROOT
253
254
        state_root_value = root(main_trie, get_storage_root=get_storage_root)
255
256
        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:
260
    <snip>
264
    del state._main_trie
265
    del state._storage_tries
266
    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:
270
    <snip>
281
    for address in diff.storage_clears:
282
        state._storage_tries.pop(address, None)
283
284
    for address, account in diff.account_changes.items():
285
        trie_set(state._main_trie, address, account)
286
287
    for address, slots in diff.storage_changes.items():
288
        trie = state._storage_tries.get(address)
289
        if trie is None:
290
            trie = Trie(secured=True, default=U256(0))
291
            state._storage_tries[address] = trie
292
        for key, value in slots.items():
293
            trie_set(trie, key, value)
294
        if trie._data == {}:
295
            del state._storage_tries[address]
296
297
    state._code_store.update(diff.code_changes)

store_code

Store bytecode in State.

def store_code(state: State, ​​code: Bytes) -> Hash32:
301
    <snip>
304
    code_hash = keccak256(code)
305
    if code_hash != EMPTY_CODE_HASH:
306
        state._code_store[code_hash] = code
307
    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:
315
    <snip>
320
    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:
329
    <snip>
334
    assert trie_get(state._main_trie, address) is not None
335
336
    trie = state._storage_tries.get(address)
337
    if trie is None:
338
        trie = Trie(secured=True, default=U256(0))
339
        state._storage_tries[address] = trie
340
    trie_set(trie, key, value)
341
    if trie._data == {}:
342
        del state._storage_tries[address]

state_root

Compute the state root of the current state.

def state_root(state: State) -> Root:
346
    <snip>
349
    root_value, _ = state.compute_state_root_and_trie_changes({}, {})
350
    return root_value