ethereum.state_mpt
Merkle-Patricia-Trie-backed implementation of the shared state model.
The State class here is the in-memory implementation of the
PreState protocol used on Ethereum mainnet: accounts and storage
live in Merkle Patricia Tries and the state root is the MPT
commitment. Other providers, such as databases, witnesses, or other
commitment schemes, are separate implementations of PreState.
State ¶
Contains all information that is preserved between transactions.
| 32 | @final |
|---|
| 33 | @dataclass |
|---|
class State:
_main_trie¶
| 39 | _main_trie: Trie[Address, Optional[Account]] = field( |
|---|---|
| 40 | default_factory=lambda: Trie(secured=True, default=None) |
| 41 | ) |
_storage_tries¶
| 42 | _storage_tries: Dict[Address, Trie[Bytes32, U256]] = field( |
|---|---|
| 43 | default_factory=dict |
| 44 | ) |
_code_store¶
| 45 | _code_store: Dict[Hash32, Bytes] = field( |
|---|---|
| 46 | default_factory=dict, compare=False |
| 47 | ) |
get_code ¶
Get the bytecode for a given code hash.
Return b"" for EMPTY_CODE_HASH.
get_account_optional ¶
Get the account at an address.
Return None if there is no account at the address.
get_storage ¶
Get a storage value.
Return U256(0) if the key has not been set.
account_has_storage ¶
Check whether an account has any storage.
Only needed for EIP-7610.
compute_state_root ¶
Compute the state root after applying block_diff to the
pre-state. The pre-state itself is not modified.
The diff's code_changes play no part: the Merkle Patricia
Trie commits to accounts' code hashes, never to code
contents, so account diffs alone determine the root.
Return the new state root.
def compute_state_root(self, block_diff: BlockDiff) -> Root:
| 91 | <snip> |
|---|---|
| 101 | main_trie = copy_trie(self._main_trie) |
| 102 | storage_tries = { |
| 103 | k: copy_trie(v) |
| 104 | for k, v in self._storage_tries.items() |
| 105 | if k not in block_diff.storage_clears |
| 106 | } |
| 107 | |
| 108 | for address, account in block_diff.account_changes.items(): |
| 109 | trie_set(main_trie, address, account) |
| 110 | |
| 111 | for address, slots in block_diff.storage_changes.items(): |
| 112 | trie = storage_tries.get(address) |
| 113 | if trie is None: |
| 114 | trie = Trie(secured=True, default=U256(0)) |
| 115 | storage_tries[address] = trie |
| 116 | for key, value in slots.items(): |
| 117 | trie_set(trie, key, value) |
| 118 | if trie._data == {}: |
| 119 | del storage_tries[address] |
| 120 | |
| 121 | def get_storage_root(addr: Address) -> Root: |
| 122 | if addr in storage_tries: |
| 123 | return root(storage_tries[addr]) |
| 124 | return EMPTY_TRIE_ROOT |
| 125 | |
| 126 | state_root_value = root(main_trie, get_storage_root=get_storage_root) |
| 127 | |
| 128 | return state_root_value |
close_state ¶
Free resources held by the state. Used by optimized implementations to release file descriptors.
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:
| 142 | <snip> |
|---|---|
| 153 | for address in diff.storage_clears: |
| 154 | state._storage_tries.pop(address, None) |
| 155 | |
| 156 | for address, account in diff.account_changes.items(): |
| 157 | trie_set(state._main_trie, address, account) |
| 158 | |
| 159 | for address, slots in diff.storage_changes.items(): |
| 160 | trie = state._storage_tries.get(address) |
| 161 | if trie is None: |
| 162 | trie = Trie(secured=True, default=U256(0)) |
| 163 | state._storage_tries[address] = trie |
| 164 | for key, value in slots.items(): |
| 165 | trie_set(trie, key, value) |
| 166 | if trie._data == {}: |
| 167 | del state._storage_tries[address] |
| 168 | |
| 169 | state._code_store.update(diff.code_changes) |
store_code ¶
Store bytecode in State.
set_account ¶
Set an account in a State.
Setting to None deletes the 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:
| 201 | <snip> |
|---|---|
| 206 | assert trie_get(state._main_trie, address) is not None |
| 207 | |
| 208 | trie = state._storage_tries.get(address) |
| 209 | if trie is None: |
| 210 | trie = Trie(secured=True, default=U256(0)) |
| 211 | state._storage_tries[address] = trie |
| 212 | trie_set(trie, key, value) |
| 213 | if trie._data == {}: |
| 214 | del state._storage_tries[address] |
state_root ¶
Compute the state root of the current state.