ethereum.cancun.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.

32
@dataclass
class State:

_main_trie

38
    _main_trie: Trie[Address, Optional[Account]] = field(
39
        default_factory=lambda: Trie(secured=True, default=None)
40
    )

_storage_tries

41
    _storage_tries: Dict[Address, Trie[Bytes32, U256]] = field(
42
        default_factory=dict
43
    )

_snapshots

44
    _snapshots: List[
45
        Tuple[
46
            Trie[Address, Optional[Account]],
47
            Dict[Address, Trie[Bytes32, U256]],
48
        ]
49
    ] = field(default_factory=list)

created_accounts

50
    created_accounts: Set[Address] = field(default_factory=set)

TransientStorage

Contains all information that is preserved between message calls within a transaction.

53
@dataclass
class TransientStorage:

_tries

60
    _tries: Dict[Address, Trie[Bytes32, U256]] = field(default_factory=dict)

_snapshots

61
    _snapshots: List[Dict[Address, Trie[Bytes32, U256]]] = field(
62
        default_factory=list
63
    )

close_state

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

def close_state(state: State) -> None:
67
    """
68
    Free resources held by the state. Used by optimized implementations to
69
    release file descriptors.
70
    """
71
    del state._main_trie
72
    del state._storage_tries
73
    del state._snapshots
74
    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. transient_storage : TransientStorage The transient storage of the transaction.

def begin_transaction(state: State, ​​transient_storage: TransientStorage) -> None:
80
    """
81
    Start a state transaction.
82
83
    Transactions are entirely implicit and can be nested. It is not possible to
84
    calculate the state root during a transaction.
85
86
    Parameters
87
    ----------
88
    state : State
89
        The state.
90
    transient_storage : TransientStorage
91
        The transient storage of the transaction.
92
    """
93
    state._snapshots.append(
94
        (
95
            copy_trie(state._main_trie),
96
            {k: copy_trie(t) for (k, t) in state._storage_tries.items()},
97
        )
98
    )
99
    transient_storage._snapshots.append(
100
        {k: copy_trie(t) for (k, t) in transient_storage._tries.items()}
101
    )

commit_transaction

Commit a state transaction.

Parameters

state : State The state. transient_storage : TransientStorage The transient storage of the transaction.

def commit_transaction(state: State, ​​transient_storage: TransientStorage) -> None:
107
    """
108
    Commit a state transaction.
109
110
    Parameters
111
    ----------
112
    state : State
113
        The state.
114
    transient_storage : TransientStorage
115
        The transient storage of the transaction.
116
    """
117
    state._snapshots.pop()
118
    if not state._snapshots:
119
        state.created_accounts.clear()
120
121
    transient_storage._snapshots.pop()

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. transient_storage : TransientStorage The transient storage of the transaction.

def rollback_transaction(state: State, ​​transient_storage: TransientStorage) -> None:
127
    """
128
    Rollback a state transaction, resetting the state to the point when the
129
    corresponding `start_transaction()` call was made.
130
131
    Parameters
132
    ----------
133
    state : State
134
        The state.
135
    transient_storage : TransientStorage
136
        The transient storage of the transaction.
137
    """
138
    state._main_trie, state._storage_tries = state._snapshots.pop()
139
    if not state._snapshots:
140
        state.created_accounts.clear()
141
142
    transient_storage._tries = transient_storage._snapshots.pop()

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:
146
    """
147
    Get the `Account` object at an address. Returns `EMPTY_ACCOUNT` if there
148
    is no account at the address.
149
150
    Use `get_account_optional()` if you care about the difference between a
151
    non-existent account and `EMPTY_ACCOUNT`.
152
153
    Parameters
154
    ----------
155
    state: `State`
156
        The state
157
    address : `Address`
158
        Address to lookup.
159
160
    Returns
161
    -------
162
    account : `Account`
163
        Account at address.
164
    """
165
    account = get_account_optional(state, address)
166
    if isinstance(account, Account):
167
        return account
168
    else:
169
        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]:
173
    """
174
    Get the `Account` object at an address. Returns `None` (rather than
175
    `EMPTY_ACCOUNT`) if there is no account at the address.
176
177
    Parameters
178
    ----------
179
    state: `State`
180
        The state
181
    address : `Address`
182
        Address to lookup.
183
184
    Returns
185
    -------
186
    account : `Account`
187
        Account at address.
188
    """
189
    account = trie_get(state._main_trie, address)
190
    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:
196
    """
197
    Set the `Account` object at an address. Setting to `None` deletes
198
    the account (but not its storage, see `destroy_account()`).
199
200
    Parameters
201
    ----------
202
    state: `State`
203
        The state
204
    address : `Address`
205
        Address to set.
206
    account : `Account`
207
        Account to set at address.
208
    """
209
    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:
213
    """
214
    Completely remove the account at `address` and all of its storage.
215
216
    This function is made available exclusively for the `SELFDESTRUCT`
217
    opcode. It is expected that `SELFDESTRUCT` will be disabled in a future
218
    hardfork and this function will be removed.
219
220
    Parameters
221
    ----------
222
    state: `State`
223
        The state
224
    address : `Address`
225
        Address of account to destroy.
226
    """
227
    destroy_storage(state, address)
228
    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:
232
    """
233
    Completely remove the storage at `address`.
234
235
    Parameters
236
    ----------
237
    state: `State`
238
        The state
239
    address : `Address`
240
        Address of account whose storage is to be deleted.
241
    """
242
    if address in state._storage_tries:
243
        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:
247
    """
248
    Mark an account as having been created in the current transaction.
249
    This information is used by `get_storage_original()` to handle an obscure
250
    edgecase.
251
252
    The marker is not removed even if the account creation reverts. Since the
253
    account cannot have had code prior to its creation and can't call
254
    `get_storage_original()`, this is harmless.
255
256
    Parameters
257
    ----------
258
    state: `State`
259
        The state
260
    address : `Address`
261
        Address of the account that has been created.
262
    """
263
    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: Bytes32) -> U256:
267
    """
268
    Get a value at a storage key on an account. Returns `U256(0)` if the
269
    storage key has not been set previously.
270
271
    Parameters
272
    ----------
273
    state: `State`
274
        The state
275
    address : `Address`
276
        Address of the account.
277
    key : `Bytes`
278
        Key to lookup.
279
280
    Returns
281
    -------
282
    value : `U256`
283
        Value at the key.
284
    """
285
    trie = state._storage_tries.get(address)
286
    if trie is None:
287
        return U256(0)
288
289
    value = trie_get(trie, key)
290
291
    assert isinstance(value, U256)
292
    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: Bytes32, ​​value: U256) -> None:
298
    """
299
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
300
    the key.
301
302
    Parameters
303
    ----------
304
    state: `State`
305
        The state
306
    address : `Address`
307
        Address of the account.
308
    key : `Bytes`
309
        Key to set.
310
    value : `U256`
311
        Value to set at the key.
312
    """
313
    assert trie_get(state._main_trie, address) is not None
314
315
    trie = state._storage_tries.get(address)
316
    if trie is None:
317
        trie = Trie(secured=True, default=U256(0))
318
        state._storage_tries[address] = trie
319
    trie_set(trie, key, value)
320
    if trie._data == {}:
321
        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:
325
    """
326
    Calculate the storage root of an account.
327
328
    Parameters
329
    ----------
330
    state:
331
        The state
332
    address :
333
        Address of the account.
334
335
    Returns
336
    -------
337
    root : `Root`
338
        Storage root of the account.
339
    """
340
    assert not state._snapshots
341
    if address in state._storage_tries:
342
        return root(state._storage_tries[address])
343
    else:
344
        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:
348
    """
349
    Calculate the state root.
350
351
    Parameters
352
    ----------
353
    state:
354
        The current state.
355
356
    Returns
357
    -------
358
    root : `Root`
359
        The state root.
360
    """
361
    assert not state._snapshots
362
363
    def get_storage_root(address: Address) -> Root:
364
        return storage_root(state, address)
365
366
    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:
370
    """
371
    Checks if an account exists in the state trie
372
373
    Parameters
374
    ----------
375
    state:
376
        The state
377
    address:
378
        Address of the account that needs to be checked.
379
380
    Returns
381
    -------
382
    account_exists : `bool`
383
        True if account exists in the state trie, False otherwise
384
    """
385
    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 the account has non zero nonce or non empty code, False otherwise.

def account_has_code_or_nonce(state: State, ​​address: Address) -> bool:
389
    """
390
    Checks if an account has non zero nonce or non empty code
391
392
    Parameters
393
    ----------
394
    state:
395
        The state
396
    address:
397
        Address of the account that needs to be checked.
398
399
    Returns
400
    -------
401
    has_code_or_nonce : `bool`
402
        True if the account has non zero nonce or non empty code,
403
        False otherwise.
404
    """
405
    account = get_account(state, address)
406
    return account.nonce != Uint(0) or account.code != b""

account_has_storage

Checks if an account has storage.

Parameters

state: The state address: Address of the account that needs to be checked.

Returns

has_storage : bool True if the account has storage, False otherwise.

def account_has_storage(state: State, ​​address: Address) -> bool:
410
    """
411
    Checks if an account has storage.
412
413
    Parameters
414
    ----------
415
    state:
416
        The state
417
    address:
418
        Address of the account that needs to be checked.
419
420
    Returns
421
    -------
422
    has_storage : `bool`
423
        True if the account has storage, False otherwise.
424
    """
425
    return address in state._storage_tries

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:
429
    """
430
    Checks if an account has zero nonce, empty code and zero balance.
431
432
    Parameters
433
    ----------
434
    state:
435
        The state
436
    address:
437
        Address of the account that needs to be checked.
438
439
    Returns
440
    -------
441
    is_empty : `bool`
442
        True if if an account has zero nonce, empty code and zero balance,
443
        False otherwise.
444
    """
445
    account = get_account(state, address)
446
    return (
447
        account.nonce == Uint(0)
448
        and account.code == b""
449
        and account.balance == 0
450
    )

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:
454
    """
455
    Checks if an account exists and has zero nonce, empty code and zero
456
    balance.
457
458
    Parameters
459
    ----------
460
    state:
461
        The state
462
    address:
463
        Address of the account that needs to be checked.
464
465
    Returns
466
    -------
467
    exists_and_is_empty : `bool`
468
        True if an account exists and has zero nonce, empty code and zero
469
        balance, False otherwise.
470
    """
471
    account = get_account_optional(state, address)
472
    return (
473
        account is not None
474
        and account.nonce == Uint(0)
475
        and account.code == b""
476
        and account.balance == 0
477
    )

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:
481
    """
482
    Check whether is an account is both in the state and non empty.
483
484
    Parameters
485
    ----------
486
    state:
487
        The state
488
    address:
489
        Address of the account that needs to be checked.
490
491
    Returns
492
    -------
493
    is_alive : `bool`
494
        True if the account is alive.
495
    """
496
    account = get_account_optional(state, address)
497
    if account is None:
498
        return False
499
    else:
500
        return not (
501
            account.nonce == Uint(0)
502
            and account.code == b""
503
            and account.balance == 0
504
        )

modify_state

Modify an Account in the State.

def modify_state(state: State, ​​address: Address, ​​f: Callable[[Account], None]) -> None:
510
    """
511
    Modify an `Account` in the `State`.
512
    """
513
    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:
522
    """
523
    Move funds between accounts.
524
    """
525
526
    def reduce_sender_balance(sender: Account) -> None:
527
        if sender.balance < amount:
528
            raise AssertionError
529
        sender.balance -= amount
530
531
    def increase_recipient_balance(recipient: Account) -> None:
532
        recipient.balance += amount
533
534
    modify_state(state, sender_address, reduce_sender_balance)
535
    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:
542
    """
543
    Increase the balance of the withdrawing account.
544
    """
545
546
    def increase_recipient_balance(recipient: Account) -> None:
547
        recipient.balance += wd.amount * U256(10**9)
548
549
    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:
553
    """
554
    Sets the balance of an account.
555
556
    Parameters
557
    ----------
558
    state:
559
        The current state.
560
561
    address:
562
        Address of the account whose nonce needs to be incremented.
563
564
    amount:
565
        The amount that needs to set in balance.
566
    """
567
568
    def set_balance(account: Account) -> None:
569
        account.balance = amount
570
571
    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:
575
    """
576
    Initializes an account to state.
577
578
    Parameters
579
    ----------
580
    state:
581
        The current state.
582
583
    address:
584
        The address of the account that need to initialised.
585
    """
586
    if not account_exists(state, address):
587
        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:
591
    """
592
    Increments the nonce of an account.
593
594
    Parameters
595
    ----------
596
    state:
597
        The current state.
598
599
    address:
600
        Address of the account whose nonce needs to be incremented.
601
    """
602
603
    def increase_nonce(sender: Account) -> None:
604
        sender.nonce += Uint(1)
605
606
    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:
610
    """
611
    Sets Account code.
612
613
    Parameters
614
    ----------
615
    state:
616
        The current state.
617
618
    address:
619
        Address of the account whose code needs to be update.
620
621
    code:
622
        The bytecode that needs to be set.
623
    """
624
625
    def write_code(sender: Account) -> None:
626
        sender.code = code
627
628
    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: Bytes32) -> U256:
632
    """
633
    Get the original value in a storage slot i.e. the value before the current
634
    transaction began. This function reads the value from the snapshots taken
635
    before executing the transaction.
636
637
    Parameters
638
    ----------
639
    state:
640
        The current state.
641
    address:
642
        Address of the account to read the value from.
643
    key:
644
        Key of the storage slot.
645
    """
646
    # In the transaction where an account is created, its preexisting storage
647
    # is ignored.
648
    if address in state.created_accounts:
649
        return U256(0)
650
651
    _, original_trie = state._snapshots[0]
652
    original_account_trie = original_trie.get(address)
653
654
    if original_account_trie is None:
655
        original_value = U256(0)
656
    else:
657
        original_value = trie_get(original_account_trie, key)
658
659
    assert isinstance(original_value, U256)
660
661
    return original_value

get_transient_storage

Get a value at a storage key on an account from transient storage. Returns U256(0) if the storage key has not been set previously. Parameters

transient_storage: TransientStorage The transient storage address : Address Address of the account. key : Bytes Key to lookup. Returns

value : U256 Value at the key.

def get_transient_storage(transient_storage: TransientStorage, ​​address: Address, ​​key: Bytes32) -> U256:
667
    """
668
    Get a value at a storage key on an account from transient storage.
669
    Returns `U256(0)` if the storage key has not been set previously.
670
    Parameters
671
    ----------
672
    transient_storage: `TransientStorage`
673
        The transient storage
674
    address : `Address`
675
        Address of the account.
676
    key : `Bytes`
677
        Key to lookup.
678
    Returns
679
    -------
680
    value : `U256`
681
        Value at the key.
682
    """
683
    trie = transient_storage._tries.get(address)
684
    if trie is None:
685
        return U256(0)
686
687
    value = trie_get(trie, key)
688
689
    assert isinstance(value, U256)
690
    return value

set_transient_storage

Set a value at a storage key on an account. Setting to U256(0) deletes the key. Parameters

transient_storage: TransientStorage The transient storage address : Address Address of the account. key : Bytes Key to set. value : U256 Value to set at the key.

def set_transient_storage(transient_storage: TransientStorage, ​​address: Address, ​​key: Bytes32, ​​value: U256) -> None:
699
    """
700
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
701
    the key.
702
    Parameters
703
    ----------
704
    transient_storage: `TransientStorage`
705
        The transient storage
706
    address : `Address`
707
        Address of the account.
708
    key : `Bytes`
709
        Key to set.
710
    value : `U256`
711
        Value to set at the key.
712
    """
713
    trie = transient_storage._tries.get(address)
714
    if trie is None:
715
        trie = Trie(secured=True, default=U256(0))
716
        transient_storage._tries[address] = trie
717
    trie_set(trie, key, value)
718
    if trie._data == {}:
719
        del transient_storage._tries[address]

destroy_touched_empty_accounts

Destroy all touched accounts that are empty. Parameters

state: State The current state. touched_accounts: Set[Address] All the accounts that have been touched in the current transaction.

def destroy_touched_empty_accounts(state: State, ​​touched_accounts: Set[Address]) -> None:
725
    """
726
    Destroy all touched accounts that are empty.
727
    Parameters
728
    ----------
729
    state: `State`
730
        The current state.
731
    touched_accounts: `Set[Address]`
732
        All the accounts that have been touched in the current transaction.
733
    """
734
    for address in touched_accounts:
735
        if account_exists_and_is_empty(state, address):
736
            destroy_account(state, address)