ethereum.shanghai.state
State ^^^^^
.. contents:: Table of Contents :backlinks: none :local:
Introduction
The state contains all information that is preserved between transactions.
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
.
State
Contains all information that is preserved between transactions.
31 | @dataclass |
---|
class State:
_main_trie
37 | _main_trie: Trie[Address, Optional[Account]] = field( |
---|---|
38 | default_factory=lambda: Trie(secured=True, default=None) |
39 | ) |
_storage_tries
40 | _storage_tries: Dict[Address, Trie[Bytes, U256]] = field( |
---|---|
41 | default_factory=dict |
42 | ) |
_snapshots
43 | _snapshots: List[ |
---|---|
44 | Tuple[ |
45 | Trie[Address, Optional[Account]], Dict[Address, Trie[Bytes, U256]] |
46 | ] |
47 | ] = field(default_factory=list) |
created_accounts
48 | created_accounts: Set[Address] = field(default_factory=set) |
---|
close_state
Free resources held by the state. Used by optimized implementations to release file descriptors.
def close_state(state: State) -> None:
52 | """ |
---|---|
53 | Free resources held by the state. Used by optimized implementations to |
54 | release file descriptors. |
55 | """ |
56 | del state._main_trie |
57 | del state._storage_tries |
58 | del state._snapshots |
59 | del state.created_accounts |
begin_transaction
Start a state transaction.
Transactions are entirely implicit and can be nested. It is not possible to calculate the state root during a transaction.
Parameters
state : State The state.
def begin_transaction(state: State) -> None:
63 | """ |
---|---|
64 | Start a state transaction. |
65 |
|
66 | Transactions are entirely implicit and can be nested. It is not possible to |
67 | calculate the state root during a transaction. |
68 |
|
69 | Parameters |
70 | ---------- |
71 | state : State |
72 | The state. |
73 | """ |
74 | state._snapshots.append( |
75 | ( |
76 | copy_trie(state._main_trie), |
77 | {k: copy_trie(t) for (k, t) in state._storage_tries.items()}, |
78 | ) |
79 | ) |
commit_transaction
Commit a state transaction.
Parameters
state : State The state.
def commit_transaction(state: State) -> None:
83 | """ |
---|---|
84 | Commit a state transaction. |
85 |
|
86 | Parameters |
87 | ---------- |
88 | state : State |
89 | The state. |
90 | """ |
91 | state._snapshots.pop() |
92 | if not state._snapshots: |
93 | state.created_accounts.clear() |
rollback_transaction
Rollback a state transaction, resetting the state to the point when the
corresponding start_transaction()
call was made.
Parameters
state : State The state.
def rollback_transaction(state: State) -> None:
97 | """ |
---|---|
98 | Rollback a state transaction, resetting the state to the point when the |
99 | corresponding `start_transaction()` call was made. |
100 |
|
101 | Parameters |
102 | ---------- |
103 | state : State |
104 | The state. |
105 | """ |
106 | state._main_trie, state._storage_tries = state._snapshots.pop() |
107 | if not state._snapshots: |
108 | state.created_accounts.clear() |
get_account
Get the Account
object at an address. Returns EMPTY_ACCOUNT
if there
is no account at the address.
Use get_account_optional()
if you care about the difference between a
non-existent account and EMPTY_ACCOUNT
.
Parameters
state: State
The state
address : Address
Address to lookup.
Returns
account : Account
Account at address.
def get_account(state: State, address: Address) -> Account:
112 | """ |
---|---|
113 | Get the `Account` object at an address. Returns `EMPTY_ACCOUNT` if there |
114 | is no account at the address. |
115 |
|
116 | Use `get_account_optional()` if you care about the difference between a |
117 | non-existent account and `EMPTY_ACCOUNT`. |
118 |
|
119 | Parameters |
120 | ---------- |
121 | state: `State` |
122 | The state |
123 | address : `Address` |
124 | Address to lookup. |
125 |
|
126 | Returns |
127 | ------- |
128 | account : `Account` |
129 | Account at address. |
130 | """ |
131 | account = get_account_optional(state, address) |
132 | if isinstance(account, Account): |
133 | return account |
134 | else: |
135 | return EMPTY_ACCOUNT |
get_account_optional
Get the Account
object at an address. Returns None
(rather than
EMPTY_ACCOUNT
) if there is no account at the address.
Parameters
state: State
The state
address : Address
Address to lookup.
Returns
account : Account
Account at address.
def get_account_optional(state: State, address: Address) -> Optional[Account]:
139 | """ |
---|---|
140 | Get the `Account` object at an address. Returns `None` (rather than |
141 | `EMPTY_ACCOUNT`) if there is no account at the address. |
142 |
|
143 | Parameters |
144 | ---------- |
145 | state: `State` |
146 | The state |
147 | address : `Address` |
148 | Address to lookup. |
149 |
|
150 | Returns |
151 | ------- |
152 | account : `Account` |
153 | Account at address. |
154 | """ |
155 | account = trie_get(state._main_trie, address) |
156 | return account |
set_account
Set the Account
object at an address. Setting to None
deletes
the account (but not its storage, see destroy_account()
).
Parameters
state: State
The state
address : Address
Address to set.
account : Account
Account to set at address.
def set_account(state: State, address: Address, account: Optional[Account]) -> None:
162 | """ |
---|---|
163 | Set the `Account` object at an address. Setting to `None` deletes |
164 | the account (but not its storage, see `destroy_account()`). |
165 |
|
166 | Parameters |
167 | ---------- |
168 | state: `State` |
169 | The state |
170 | address : `Address` |
171 | Address to set. |
172 | account : `Account` |
173 | Account to set at address. |
174 | """ |
175 | trie_set(state._main_trie, address, account) |
destroy_account
Completely remove the account at address
and all of its storage.
This function is made available exclusively for the SELFDESTRUCT
opcode. It is expected that SELFDESTRUCT
will be disabled in a future
hardfork and this function will be removed.
Parameters
state: State
The state
address : Address
Address of account to destroy.
def destroy_account(state: State, address: Address) -> None:
179 | """ |
---|---|
180 | Completely remove the account at `address` and all of its storage. |
181 |
|
182 | This function is made available exclusively for the `SELFDESTRUCT` |
183 | opcode. It is expected that `SELFDESTRUCT` will be disabled in a future |
184 | hardfork and this function will be removed. |
185 |
|
186 | Parameters |
187 | ---------- |
188 | state: `State` |
189 | The state |
190 | address : `Address` |
191 | Address of account to destroy. |
192 | """ |
193 | destroy_storage(state, address) |
194 | set_account(state, address, None) |
destroy_storage
Completely remove the storage at address
.
Parameters
state: State
The state
address : Address
Address of account whose storage is to be deleted.
def destroy_storage(state: State, address: Address) -> None:
198 | """ |
---|---|
199 | Completely remove the storage at `address`. |
200 |
|
201 | Parameters |
202 | ---------- |
203 | state: `State` |
204 | The state |
205 | address : `Address` |
206 | Address of account whose storage is to be deleted. |
207 | """ |
208 | if address in state._storage_tries: |
209 | del state._storage_tries[address] |
mark_account_created
Mark an account as having been created in the current transaction.
This information is used by get_storage_original()
to handle an obscure
edgecase.
The marker is not removed even if the account creation reverts. Since the
account cannot have had code prior to its creation and can't call
get_storage_original()
, this is harmless.
Parameters
state: State
The state
address : Address
Address of the account that has been created.
def mark_account_created(state: State, address: Address) -> None:
213 | """ |
---|---|
214 | Mark an account as having been created in the current transaction. |
215 | This information is used by `get_storage_original()` to handle an obscure |
216 | edgecase. |
217 |
|
218 | The marker is not removed even if the account creation reverts. Since the |
219 | account cannot have had code prior to its creation and can't call |
220 | `get_storage_original()`, this is harmless. |
221 |
|
222 | Parameters |
223 | ---------- |
224 | state: `State` |
225 | The state |
226 | address : `Address` |
227 | Address of the account that has been created. |
228 | """ |
229 | state.created_accounts.add(address) |
get_storage
Get a value at a storage key on an account. Returns U256(0)
if the
storage key has not been set previously.
Parameters
state: State
The state
address : Address
Address of the account.
key : Bytes
Key to lookup.
Returns
value : U256
Value at the key.
def get_storage(state: State, address: Address, key: Bytes) -> U256:
233 | """ |
---|---|
234 | Get a value at a storage key on an account. Returns `U256(0)` if the |
235 | storage key has not been set previously. |
236 |
|
237 | Parameters |
238 | ---------- |
239 | state: `State` |
240 | The state |
241 | address : `Address` |
242 | Address of the account. |
243 | key : `Bytes` |
244 | Key to lookup. |
245 |
|
246 | Returns |
247 | ------- |
248 | value : `U256` |
249 | Value at the key. |
250 | """ |
251 | trie = state._storage_tries.get(address) |
252 | if trie is None: |
253 | return U256(0) |
254 | |
255 | value = trie_get(trie, key) |
256 | |
257 | assert isinstance(value, U256) |
258 | return value |
set_storage
Set a value at a storage key on an account. Setting to U256(0)
deletes
the key.
Parameters
state: State
The state
address : Address
Address of the account.
key : Bytes
Key to set.
value : U256
Value to set at the key.
def set_storage(state: State, address: Address, key: Bytes, value: U256) -> None:
264 | """ |
---|---|
265 | Set a value at a storage key on an account. Setting to `U256(0)` deletes |
266 | the key. |
267 |
|
268 | Parameters |
269 | ---------- |
270 | state: `State` |
271 | The state |
272 | address : `Address` |
273 | Address of the account. |
274 | key : `Bytes` |
275 | Key to set. |
276 | value : `U256` |
277 | Value to set at the key. |
278 | """ |
279 | assert trie_get(state._main_trie, address) is not None |
280 | |
281 | trie = state._storage_tries.get(address) |
282 | if trie is None: |
283 | trie = Trie(secured=True, default=U256(0)) |
284 | state._storage_tries[address] = trie |
285 | trie_set(trie, key, value) |
286 | if trie._data == {}: |
287 | del state._storage_tries[address] |
storage_root
Calculate the storage root of an account.
Parameters
state: The state address : Address of the account.
Returns
root : Root
Storage root of the account.
def storage_root(state: State, address: Address) -> Root:
291 | """ |
---|---|
292 | Calculate the storage root of an account. |
293 |
|
294 | Parameters |
295 | ---------- |
296 | state: |
297 | The state |
298 | address : |
299 | Address of the account. |
300 |
|
301 | Returns |
302 | ------- |
303 | root : `Root` |
304 | Storage root of the account. |
305 | """ |
306 | assert not state._snapshots |
307 | if address in state._storage_tries: |
308 | return root(state._storage_tries[address]) |
309 | else: |
310 | return EMPTY_TRIE_ROOT |
state_root
Calculate the state root.
Parameters
state: The current state.
Returns
root : Root
The state root.
def state_root(state: State) -> Root:
314 | """ |
---|---|
315 | Calculate the state root. |
316 |
|
317 | Parameters |
318 | ---------- |
319 | state: |
320 | The current state. |
321 |
|
322 | Returns |
323 | ------- |
324 | root : `Root` |
325 | The state root. |
326 | """ |
327 | assert not state._snapshots |
328 | |
329 | def get_storage_root(address: Address) -> Root: |
330 | return storage_root(state, address) |
331 | |
332 | return root(state._main_trie, get_storage_root=get_storage_root) |
account_exists
Checks if an account exists in the state trie
Parameters
state: The state address: Address of the account that needs to be checked.
Returns
account_exists : bool
True if account exists in the state trie, False otherwise
def account_exists(state: State, address: Address) -> bool:
336 | """ |
---|---|
337 | Checks if an account exists in the state trie |
338 |
|
339 | Parameters |
340 | ---------- |
341 | state: |
342 | The state |
343 | address: |
344 | Address of the account that needs to be checked. |
345 |
|
346 | Returns |
347 | ------- |
348 | account_exists : `bool` |
349 | True if account exists in the state trie, False otherwise |
350 | """ |
351 | return get_account_optional(state, address) is not None |
account_has_code_or_nonce
Checks if an account has non zero nonce or non empty code
Parameters
state: The state address: Address of the account that needs to be checked.
Returns
has_code_or_nonce : bool
True if if an account has non zero nonce or non empty code,
False otherwise.
def account_has_code_or_nonce(state: State, address: Address) -> bool:
355 | """ |
---|---|
356 | Checks if an account has non zero nonce or non empty code |
357 |
|
358 | Parameters |
359 | ---------- |
360 | state: |
361 | The state |
362 | address: |
363 | Address of the account that needs to be checked. |
364 |
|
365 | Returns |
366 | ------- |
367 | has_code_or_nonce : `bool` |
368 | True if if an account has non zero nonce or non empty code, |
369 | False otherwise. |
370 | """ |
371 | account = get_account(state, address) |
372 | return account.nonce != Uint(0) or account.code != b"" |
is_account_empty
Checks if an account has zero nonce, empty code and zero balance.
Parameters
state: The state address: Address of the account that needs to be checked.
Returns
is_empty : bool
True if if an account has zero nonce, empty code and zero balance,
False otherwise.
def is_account_empty(state: State, address: Address) -> bool:
376 | """ |
---|---|
377 | Checks if an account has zero nonce, empty code and zero balance. |
378 |
|
379 | Parameters |
380 | ---------- |
381 | state: |
382 | The state |
383 | address: |
384 | Address of the account that needs to be checked. |
385 |
|
386 | Returns |
387 | ------- |
388 | is_empty : `bool` |
389 | True if if an account has zero nonce, empty code and zero balance, |
390 | False otherwise. |
391 | """ |
392 | account = get_account(state, address) |
393 | return ( |
394 | account.nonce == Uint(0) |
395 | and account.code == b"" |
396 | and account.balance == 0 |
397 | ) |
account_exists_and_is_empty
Checks if an account exists and has zero nonce, empty code and zero balance.
Parameters
state: The state address: Address of the account that needs to be checked.
Returns
exists_and_is_empty : bool
True if an account exists and has zero nonce, empty code and zero
balance, False otherwise.
def account_exists_and_is_empty(state: State, address: Address) -> bool:
401 | """ |
---|---|
402 | Checks if an account exists and has zero nonce, empty code and zero |
403 | balance. |
404 |
|
405 | Parameters |
406 | ---------- |
407 | state: |
408 | The state |
409 | address: |
410 | Address of the account that needs to be checked. |
411 |
|
412 | Returns |
413 | ------- |
414 | exists_and_is_empty : `bool` |
415 | True if an account exists and has zero nonce, empty code and zero |
416 | balance, False otherwise. |
417 | """ |
418 | account = get_account_optional(state, address) |
419 | return ( |
420 | account is not None |
421 | and account.nonce == Uint(0) |
422 | and account.code == b"" |
423 | and account.balance == 0 |
424 | ) |
is_account_alive
Check whether is an account is both in the state and non empty.
Parameters
state: The state address: Address of the account that needs to be checked.
Returns
is_alive : bool
True if the account is alive.
def is_account_alive(state: State, address: Address) -> bool:
428 | """ |
---|---|
429 | Check whether is an account is both in the state and non empty. |
430 |
|
431 | Parameters |
432 | ---------- |
433 | state: |
434 | The state |
435 | address: |
436 | Address of the account that needs to be checked. |
437 |
|
438 | Returns |
439 | ------- |
440 | is_alive : `bool` |
441 | True if the account is alive. |
442 | """ |
443 | account = get_account_optional(state, address) |
444 | if account is None: |
445 | return False |
446 | else: |
447 | return not ( |
448 | account.nonce == Uint(0) |
449 | and account.code == b"" |
450 | and account.balance == 0 |
451 | ) |
modify_state
Modify an Account
in the State
.
def modify_state(state: State, address: Address, f: Callable[[Account], None]) -> None:
457 | """ |
---|---|
458 | Modify an `Account` in the `State`. |
459 | """ |
460 | set_account(state, address, modify(get_account(state, address), f)) |
move_ether
Move funds between accounts.
def move_ether(state: State, sender_address: Address, recipient_address: Address, amount: U256) -> None:
469 | """ |
---|---|
470 | Move funds between accounts. |
471 | """ |
472 | |
473 | def reduce_sender_balance(sender: Account) -> None: |
474 | if sender.balance < amount: |
475 | raise AssertionError |
476 | sender.balance -= amount |
477 | |
478 | def increase_recipient_balance(recipient: Account) -> None: |
479 | recipient.balance += amount |
480 | |
481 | modify_state(state, sender_address, reduce_sender_balance) |
482 | modify_state(state, recipient_address, increase_recipient_balance) |
process_withdrawal
Increase the balance of the withdrawing account.
def process_withdrawal(state: State, wd: Withdrawal) -> None:
489 | """ |
---|---|
490 | Increase the balance of the withdrawing account. |
491 | """ |
492 | |
493 | def increase_recipient_balance(recipient: Account) -> None: |
494 | recipient.balance += wd.amount * U256(10**9) |
495 | |
496 | modify_state(state, wd.address, increase_recipient_balance) |
set_account_balance
Sets the balance of an account.
Parameters
state: The current state.
address: Address of the account whose nonce needs to be incremented.
amount: The amount that needs to set in balance.
def set_account_balance(state: State, address: Address, amount: U256) -> None:
500 | """ |
---|---|
501 | Sets the balance of an account. |
502 |
|
503 | Parameters |
504 | ---------- |
505 | state: |
506 | The current state. |
507 |
|
508 | address: |
509 | Address of the account whose nonce needs to be incremented. |
510 |
|
511 | amount: |
512 | The amount that needs to set in balance. |
513 | """ |
514 | |
515 | def set_balance(account: Account) -> None: |
516 | account.balance = amount |
517 | |
518 | modify_state(state, address, set_balance) |
touch_account
Initializes an account to state.
Parameters
state: The current state.
address: The address of the account that need to initialised.
def touch_account(state: State, address: Address) -> None:
522 | """ |
---|---|
523 | Initializes an account to state. |
524 |
|
525 | Parameters |
526 | ---------- |
527 | state: |
528 | The current state. |
529 |
|
530 | address: |
531 | The address of the account that need to initialised. |
532 | """ |
533 | if not account_exists(state, address): |
534 | set_account(state, address, EMPTY_ACCOUNT) |
increment_nonce
Increments the nonce of an account.
Parameters
state: The current state.
address: Address of the account whose nonce needs to be incremented.
def increment_nonce(state: State, address: Address) -> None:
538 | """ |
---|---|
539 | Increments the nonce of an account. |
540 |
|
541 | Parameters |
542 | ---------- |
543 | state: |
544 | The current state. |
545 |
|
546 | address: |
547 | Address of the account whose nonce needs to be incremented. |
548 | """ |
549 | |
550 | def increase_nonce(sender: Account) -> None: |
551 | sender.nonce += Uint(1) |
552 | |
553 | modify_state(state, address, increase_nonce) |
set_code
Sets Account code.
Parameters
state: The current state.
address: Address of the account whose code needs to be update.
code: The bytecode that needs to be set.
def set_code(state: State, address: Address, code: Bytes) -> None:
557 | """ |
---|---|
558 | Sets Account code. |
559 |
|
560 | Parameters |
561 | ---------- |
562 | state: |
563 | The current state. |
564 |
|
565 | address: |
566 | Address of the account whose code needs to be update. |
567 |
|
568 | code: |
569 | The bytecode that needs to be set. |
570 | """ |
571 | |
572 | def write_code(sender: Account) -> None: |
573 | sender.code = code |
574 | |
575 | modify_state(state, address, write_code) |
get_storage_original
Get the original value in a storage slot i.e. the value before the current transaction began. This function reads the value from the snapshots taken before executing the transaction.
Parameters
state: The current state. address: Address of the account to read the value from. key: Key of the storage slot.
def get_storage_original(state: State, address: Address, key: Bytes) -> U256:
579 | """ |
---|---|
580 | Get the original value in a storage slot i.e. the value before the current |
581 | transaction began. This function reads the value from the snapshots taken |
582 | before executing the transaction. |
583 |
|
584 | Parameters |
585 | ---------- |
586 | state: |
587 | The current state. |
588 | address: |
589 | Address of the account to read the value from. |
590 | key: |
591 | Key of the storage slot. |
592 | """ |
593 | # In the transaction where an account is created, its preexisting storage |
594 | # is ignored. |
595 | if address in state.created_accounts: |
596 | return U256(0) |
597 | |
598 | _, original_trie = state._snapshots[0] |
599 | original_account_trie = original_trie.get(address) |
600 | |
601 | if original_account_trie is None: |
602 | original_value = U256(0) |
603 | else: |
604 | original_value = trie_get(original_account_trie, key) |
605 | |
606 | assert isinstance(original_value, U256) |
607 | |
608 | return original_value |