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.

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)

TransientStorage

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

51
@dataclass
class TransientStorage:

_tries

58
    _tries: Dict[Address, Trie[Bytes, U256]] = field(default_factory=dict)

_snapshots

59
    _snapshots: List[Dict[Address, Trie[Bytes, U256]]] = field(
60
        default_factory=list
61
    )

close_state

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

def close_state(state: State) -> None:
65
    """
66
    Free resources held by the state. Used by optimized implementations to
67
    release file descriptors.
68
    """
69
    del state._main_trie
70
    del state._storage_tries
71
    del state._snapshots
72
    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:
78
    """
79
    Start a state transaction.
80
81
    Transactions are entirely implicit and can be nested. It is not possible to
82
    calculate the state root during a transaction.
83
84
    Parameters
85
    ----------
86
    state : State
87
        The state.
88
    transient_storage : TransientStorage
89
        The transient storage of the transaction.
90
    """
91
    state._snapshots.append(
92
        (
93
            copy_trie(state._main_trie),
94
            {k: copy_trie(t) for (k, t) in state._storage_tries.items()},
95
        )
96
    )
97
    transient_storage._snapshots.append(
98
        {k: copy_trie(t) for (k, t) in transient_storage._tries.items()}
99
    )

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:
105
    """
106
    Commit a state transaction.
107
108
    Parameters
109
    ----------
110
    state : State
111
        The state.
112
    transient_storage : TransientStorage
113
        The transient storage of the transaction.
114
    """
115
    state._snapshots.pop()
116
    if not state._snapshots:
117
        state.created_accounts.clear()
118
119
    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:
125
    """
126
    Rollback a state transaction, resetting the state to the point when the
127
    corresponding `start_transaction()` call was made.
128
129
    Parameters
130
    ----------
131
    state : State
132
        The state.
133
    transient_storage : TransientStorage
134
        The transient storage of the transaction.
135
    """
136
    state._main_trie, state._storage_tries = state._snapshots.pop()
137
    if not state._snapshots:
138
        state.created_accounts.clear()
139
140
    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:
144
    """
145
    Get the `Account` object at an address. Returns `EMPTY_ACCOUNT` if there
146
    is no account at the address.
147
148
    Use `get_account_optional()` if you care about the difference between a
149
    non-existent account and `EMPTY_ACCOUNT`.
150
151
    Parameters
152
    ----------
153
    state: `State`
154
        The state
155
    address : `Address`
156
        Address to lookup.
157
158
    Returns
159
    -------
160
    account : `Account`
161
        Account at address.
162
    """
163
    account = get_account_optional(state, address)
164
    if isinstance(account, Account):
165
        return account
166
    else:
167
        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]:
171
    """
172
    Get the `Account` object at an address. Returns `None` (rather than
173
    `EMPTY_ACCOUNT`) if there is no account at the address.
174
175
    Parameters
176
    ----------
177
    state: `State`
178
        The state
179
    address : `Address`
180
        Address to lookup.
181
182
    Returns
183
    -------
184
    account : `Account`
185
        Account at address.
186
    """
187
    account = trie_get(state._main_trie, address)
188
    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:
194
    """
195
    Set the `Account` object at an address. Setting to `None` deletes
196
    the account (but not its storage, see `destroy_account()`).
197
198
    Parameters
199
    ----------
200
    state: `State`
201
        The state
202
    address : `Address`
203
        Address to set.
204
    account : `Account`
205
        Account to set at address.
206
    """
207
    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:
211
    """
212
    Completely remove the account at `address` and all of its storage.
213
214
    This function is made available exclusively for the `SELFDESTRUCT`
215
    opcode. It is expected that `SELFDESTRUCT` will be disabled in a future
216
    hardfork and this function will be removed.
217
218
    Parameters
219
    ----------
220
    state: `State`
221
        The state
222
    address : `Address`
223
        Address of account to destroy.
224
    """
225
    destroy_storage(state, address)
226
    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:
230
    """
231
    Completely remove the storage at `address`.
232
233
    Parameters
234
    ----------
235
    state: `State`
236
        The state
237
    address : `Address`
238
        Address of account whose storage is to be deleted.
239
    """
240
    if address in state._storage_tries:
241
        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:
245
    """
246
    Mark an account as having been created in the current transaction.
247
    This information is used by `get_storage_original()` to handle an obscure
248
    edgecase.
249
250
    The marker is not removed even if the account creation reverts. Since the
251
    account cannot have had code prior to its creation and can't call
252
    `get_storage_original()`, this is harmless.
253
254
    Parameters
255
    ----------
256
    state: `State`
257
        The state
258
    address : `Address`
259
        Address of the account that has been created.
260
    """
261
    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:
265
    """
266
    Get a value at a storage key on an account. Returns `U256(0)` if the
267
    storage key has not been set previously.
268
269
    Parameters
270
    ----------
271
    state: `State`
272
        The state
273
    address : `Address`
274
        Address of the account.
275
    key : `Bytes`
276
        Key to lookup.
277
278
    Returns
279
    -------
280
    value : `U256`
281
        Value at the key.
282
    """
283
    trie = state._storage_tries.get(address)
284
    if trie is None:
285
        return U256(0)
286
287
    value = trie_get(trie, key)
288
289
    assert isinstance(value, U256)
290
    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:
296
    """
297
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
298
    the key.
299
300
    Parameters
301
    ----------
302
    state: `State`
303
        The state
304
    address : `Address`
305
        Address of the account.
306
    key : `Bytes`
307
        Key to set.
308
    value : `U256`
309
        Value to set at the key.
310
    """
311
    assert trie_get(state._main_trie, address) is not None
312
313
    trie = state._storage_tries.get(address)
314
    if trie is None:
315
        trie = Trie(secured=True, default=U256(0))
316
        state._storage_tries[address] = trie
317
    trie_set(trie, key, value)
318
    if trie._data == {}:
319
        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:
323
    """
324
    Calculate the storage root of an account.
325
326
    Parameters
327
    ----------
328
    state:
329
        The state
330
    address :
331
        Address of the account.
332
333
    Returns
334
    -------
335
    root : `Root`
336
        Storage root of the account.
337
    """
338
    assert not state._snapshots
339
    if address in state._storage_tries:
340
        return root(state._storage_tries[address])
341
    else:
342
        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:
346
    """
347
    Calculate the state root.
348
349
    Parameters
350
    ----------
351
    state:
352
        The current state.
353
354
    Returns
355
    -------
356
    root : `Root`
357
        The state root.
358
    """
359
    assert not state._snapshots
360
361
    def get_storage_root(address: Address) -> Root:
362
        return storage_root(state, address)
363
364
    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:
368
    """
369
    Checks if an account exists in the state trie
370
371
    Parameters
372
    ----------
373
    state:
374
        The state
375
    address:
376
        Address of the account that needs to be checked.
377
378
    Returns
379
    -------
380
    account_exists : `bool`
381
        True if account exists in the state trie, False otherwise
382
    """
383
    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:
387
    """
388
    Checks if an account has non zero nonce or non empty code
389
390
    Parameters
391
    ----------
392
    state:
393
        The state
394
    address:
395
        Address of the account that needs to be checked.
396
397
    Returns
398
    -------
399
    has_code_or_nonce : `bool`
400
        True if if an account has non zero nonce or non empty code,
401
        False otherwise.
402
    """
403
    account = get_account(state, address)
404
    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:
408
    """
409
    Checks if an account has zero nonce, empty code and zero balance.
410
411
    Parameters
412
    ----------
413
    state:
414
        The state
415
    address:
416
        Address of the account that needs to be checked.
417
418
    Returns
419
    -------
420
    is_empty : `bool`
421
        True if if an account has zero nonce, empty code and zero balance,
422
        False otherwise.
423
    """
424
    account = get_account(state, address)
425
    return (
426
        account.nonce == Uint(0)
427
        and account.code == b""
428
        and account.balance == 0
429
    )

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:
433
    """
434
    Checks if an account exists and has zero nonce, empty code and zero
435
    balance.
436
437
    Parameters
438
    ----------
439
    state:
440
        The state
441
    address:
442
        Address of the account that needs to be checked.
443
444
    Returns
445
    -------
446
    exists_and_is_empty : `bool`
447
        True if an account exists and has zero nonce, empty code and zero
448
        balance, False otherwise.
449
    """
450
    account = get_account_optional(state, address)
451
    return (
452
        account is not None
453
        and account.nonce == Uint(0)
454
        and account.code == b""
455
        and account.balance == 0
456
    )

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:
460
    """
461
    Check whether is an account is both in the state and non empty.
462
463
    Parameters
464
    ----------
465
    state:
466
        The state
467
    address:
468
        Address of the account that needs to be checked.
469
470
    Returns
471
    -------
472
    is_alive : `bool`
473
        True if the account is alive.
474
    """
475
    account = get_account_optional(state, address)
476
    if account is None:
477
        return False
478
    else:
479
        return not (
480
            account.nonce == Uint(0)
481
            and account.code == b""
482
            and account.balance == 0
483
        )

modify_state

Modify an Account in the State.

def modify_state(state: State, ​​address: Address, ​​f: Callable[[Account], None]) -> None:
489
    """
490
    Modify an `Account` in the `State`.
491
    """
492
    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:
501
    """
502
    Move funds between accounts.
503
    """
504
505
    def reduce_sender_balance(sender: Account) -> None:
506
        if sender.balance < amount:
507
            raise AssertionError
508
        sender.balance -= amount
509
510
    def increase_recipient_balance(recipient: Account) -> None:
511
        recipient.balance += amount
512
513
    modify_state(state, sender_address, reduce_sender_balance)
514
    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:
521
    """
522
    Increase the balance of the withdrawing account.
523
    """
524
525
    def increase_recipient_balance(recipient: Account) -> None:
526
        recipient.balance += wd.amount * U256(10**9)
527
528
    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:
532
    """
533
    Sets the balance of an account.
534
535
    Parameters
536
    ----------
537
    state:
538
        The current state.
539
540
    address:
541
        Address of the account whose nonce needs to be incremented.
542
543
    amount:
544
        The amount that needs to set in balance.
545
    """
546
547
    def set_balance(account: Account) -> None:
548
        account.balance = amount
549
550
    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:
554
    """
555
    Initializes an account to state.
556
557
    Parameters
558
    ----------
559
    state:
560
        The current state.
561
562
    address:
563
        The address of the account that need to initialised.
564
    """
565
    if not account_exists(state, address):
566
        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:
570
    """
571
    Increments the nonce of an account.
572
573
    Parameters
574
    ----------
575
    state:
576
        The current state.
577
578
    address:
579
        Address of the account whose nonce needs to be incremented.
580
    """
581
582
    def increase_nonce(sender: Account) -> None:
583
        sender.nonce += Uint(1)
584
585
    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:
589
    """
590
    Sets Account code.
591
592
    Parameters
593
    ----------
594
    state:
595
        The current state.
596
597
    address:
598
        Address of the account whose code needs to be update.
599
600
    code:
601
        The bytecode that needs to be set.
602
    """
603
604
    def write_code(sender: Account) -> None:
605
        sender.code = code
606
607
    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:
611
    """
612
    Get the original value in a storage slot i.e. the value before the current
613
    transaction began. This function reads the value from the snapshots taken
614
    before executing the transaction.
615
616
    Parameters
617
    ----------
618
    state:
619
        The current state.
620
    address:
621
        Address of the account to read the value from.
622
    key:
623
        Key of the storage slot.
624
    """
625
    # In the transaction where an account is created, its preexisting storage
626
    # is ignored.
627
    if address in state.created_accounts:
628
        return U256(0)
629
630
    _, original_trie = state._snapshots[0]
631
    original_account_trie = original_trie.get(address)
632
633
    if original_account_trie is None:
634
        original_value = U256(0)
635
    else:
636
        original_value = trie_get(original_account_trie, key)
637
638
    assert isinstance(original_value, U256)
639
640
    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: Bytes) -> U256:
646
    """
647
    Get a value at a storage key on an account from transient storage.
648
    Returns `U256(0)` if the storage key has not been set previously.
649
    Parameters
650
    ----------
651
    transient_storage: `TransientStorage`
652
        The transient storage
653
    address : `Address`
654
        Address of the account.
655
    key : `Bytes`
656
        Key to lookup.
657
    Returns
658
    -------
659
    value : `U256`
660
        Value at the key.
661
    """
662
    trie = transient_storage._tries.get(address)
663
    if trie is None:
664
        return U256(0)
665
666
    value = trie_get(trie, key)
667
668
    assert isinstance(value, U256)
669
    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: Bytes, ​​value: U256) -> None:
678
    """
679
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
680
    the key.
681
    Parameters
682
    ----------
683
    transient_storage: `TransientStorage`
684
        The transient storage
685
    address : `Address`
686
        Address of the account.
687
    key : `Bytes`
688
        Key to set.
689
    value : `U256`
690
        Value to set at the key.
691
    """
692
    trie = transient_storage._tries.get(address)
693
    if trie is None:
694
        trie = Trie(secured=True, default=U256(0))
695
        transient_storage._tries[address] = trie
696
    trie_set(trie, key, value)
697
    if trie._data == {}:
698
        del transient_storage._tries[address]

destroy_touched_empty_accounts

Destroy all touched accounts that are empty. Parameters

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

def destroy_touched_empty_accounts(state: State, ​​touched_accounts: Iterable[Address]) -> None:
704
    """
705
    Destroy all touched accounts that are empty.
706
    Parameters
707
    ----------
708
    state: `State`
709
        The current state.
710
    touched_accounts: `Iterable[Address]`
711
        All the accounts that have been touched in the current transaction.
712
    """
713
    for address in touched_accounts:
714
        if account_exists_and_is_empty(state, address):
715
            destroy_account(state, address)