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[Bytes32, U256]] = field(
41
        default_factory=dict
42
    )

_snapshots

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

created_accounts

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

TransientStorage

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

52
@dataclass
class TransientStorage:

_tries

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

_snapshots

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

close_state

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

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

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

def is_account_empty(state: State, ​​address: Address) -> bool:
428
    """
429
    Checks if an account has zero nonce, empty code and zero balance.
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_empty : `bool`
441
        True if an account has zero nonce, empty code and zero balance,
442
        False otherwise.
443
    """
444
    account = get_account(state, address)
445
    return (
446
        account.nonce == Uint(0)
447
        and account.code == b""
448
        and account.balance == 0
449
    )

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

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:
480
    """
481
    Check whether is an account is both in the state and non empty.
482
483
    Parameters
484
    ----------
485
    state:
486
        The state
487
    address:
488
        Address of the account that needs to be checked.
489
490
    Returns
491
    -------
492
    is_alive : `bool`
493
        True if the account is alive.
494
    """
495
    account = get_account_optional(state, address)
496
    return account is not None and account != EMPTY_ACCOUNT

modify_state

Modify an Account in the State.

def modify_state(state: State, ​​address: Address, ​​f: Callable[[Account], None]) -> None:
502
    """
503
    Modify an `Account` in the `State`.
504
    """
505
    set_account(state, address, modify(get_account(state, address), f))
506
    if account_exists_and_is_empty(state, address):
507
        destroy_account(state, address)

move_ether

Move funds between accounts.

def move_ether(state: State, ​​sender_address: Address, ​​recipient_address: Address, ​​amount: U256) -> None:
516
    """
517
    Move funds between accounts.
518
    """
519
520
    def reduce_sender_balance(sender: Account) -> None:
521
        if sender.balance < amount:
522
            raise AssertionError
523
        sender.balance -= amount
524
525
    def increase_recipient_balance(recipient: Account) -> None:
526
        recipient.balance += amount
527
528
    modify_state(state, sender_address, reduce_sender_balance)
529
    modify_state(state, recipient_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:
533
    """
534
    Sets the balance of an account.
535
536
    Parameters
537
    ----------
538
    state:
539
        The current state.
540
541
    address:
542
        Address of the account whose nonce needs to be incremented.
543
544
    amount:
545
        The amount that needs to set in balance.
546
    """
547
548
    def set_balance(account: Account) -> None:
549
        account.balance = amount
550
551
    modify_state(state, address, set_balance)

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:
555
    """
556
    Increments the nonce of an account.
557
558
    Parameters
559
    ----------
560
    state:
561
        The current state.
562
563
    address:
564
        Address of the account whose nonce needs to be incremented.
565
    """
566
567
    def increase_nonce(sender: Account) -> None:
568
        sender.nonce += Uint(1)
569
570
    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:
574
    """
575
    Sets Account code.
576
577
    Parameters
578
    ----------
579
    state:
580
        The current state.
581
582
    address:
583
        Address of the account whose code needs to be update.
584
585
    code:
586
        The bytecode that needs to be set.
587
    """
588
589
    def write_code(sender: Account) -> None:
590
        sender.code = code
591
592
    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:
596
    """
597
    Get the original value in a storage slot i.e. the value before the current
598
    transaction began. This function reads the value from the snapshots taken
599
    before executing the transaction.
600
601
    Parameters
602
    ----------
603
    state:
604
        The current state.
605
    address:
606
        Address of the account to read the value from.
607
    key:
608
        Key of the storage slot.
609
    """
610
    # In the transaction where an account is created, its preexisting storage
611
    # is ignored.
612
    if address in state.created_accounts:
613
        return U256(0)
614
615
    _, original_trie = state._snapshots[0]
616
    original_account_trie = original_trie.get(address)
617
618
    if original_account_trie is None:
619
        original_value = U256(0)
620
    else:
621
        original_value = trie_get(original_account_trie, key)
622
623
    assert isinstance(original_value, U256)
624
625
    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:
631
    """
632
    Get a value at a storage key on an account from transient storage.
633
    Returns `U256(0)` if the storage key has not been set previously.
634
    Parameters
635
    ----------
636
    transient_storage: `TransientStorage`
637
        The transient storage
638
    address : `Address`
639
        Address of the account.
640
    key : `Bytes`
641
        Key to lookup.
642
    Returns
643
    -------
644
    value : `U256`
645
        Value at the key.
646
    """
647
    trie = transient_storage._tries.get(address)
648
    if trie is None:
649
        return U256(0)
650
651
    value = trie_get(trie, key)
652
653
    assert isinstance(value, U256)
654
    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:
663
    """
664
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
665
    the key.
666
    Parameters
667
    ----------
668
    transient_storage: `TransientStorage`
669
        The transient storage
670
    address : `Address`
671
        Address of the account.
672
    key : `Bytes`
673
        Key to set.
674
    value : `U256`
675
        Value to set at the key.
676
    """
677
    trie = transient_storage._tries.get(address)
678
    if trie is None:
679
        trie = Trie(secured=True, default=U256(0))
680
        transient_storage._tries[address] = trie
681
    trie_set(trie, key, value)
682
    if trie._data == {}:
683
        del transient_storage._tries[address]