ethereum.forks.gray_glacier.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)

_code_store

51
    _code_store: Dict[Hash32, Bytes] = field(
52
        default_factory=dict, compare=False
53
    )

close_state

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

def close_state(state: State) -> None:
57
    """
58
    Free resources held by the state. Used by optimized implementations to
59
    release file descriptors.
60
    """
61
    del state._main_trie
62
    del state._storage_tries
63
    del state._snapshots
64
    del state.created_accounts
65
    del state._code_store

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:
69
    """
70
    Start a state transaction.
71
72
    Transactions are entirely implicit and can be nested. It is not possible to
73
    calculate the state root during a transaction.
74
75
    Parameters
76
    ----------
77
    state : State
78
        The state.
79
80
    """
81
    state._snapshots.append(
82
        (
83
            copy_trie(state._main_trie),
84
            {k: copy_trie(t) for (k, t) in state._storage_tries.items()},
85
        )
86
    )

commit_transaction

Commit a state transaction.

Parameters

state : State The state.

def commit_transaction(state: State) -> None:
90
    """
91
    Commit a state transaction.
92
93
    Parameters
94
    ----------
95
    state : State
96
        The state.
97
98
    """
99
    state._snapshots.pop()
100
    if not state._snapshots:
101
        state.created_accounts.clear()

rollback_transaction

Rollback a state transaction, resetting the state to the point when the corresponding begin_transaction() call was made.

Parameters

state : State The state.

def rollback_transaction(state: State) -> None:
105
    """
106
    Rollback a state transaction, resetting the state to the point when the
107
    corresponding `begin_transaction()` call was made.
108
109
    Parameters
110
    ----------
111
    state : State
112
        The state.
113
114
    """
115
    state._main_trie, state._storage_tries = state._snapshots.pop()
116
    if not state._snapshots:
117
        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:
121
    """
122
    Get the `Account` object at an address. Returns `EMPTY_ACCOUNT` if there
123
    is no account at the address.
124
125
    Use `get_account_optional()` if you care about the difference between a
126
    non-existent account and `EMPTY_ACCOUNT`.
127
128
    Parameters
129
    ----------
130
    state: `State`
131
        The state
132
    address : `Address`
133
        Address to lookup.
134
135
    Returns
136
    -------
137
    account : `Account`
138
        Account at address.
139
140
    """
141
    account = get_account_optional(state, address)
142
    if isinstance(account, Account):
143
        return account
144
    else:
145
        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]:
149
    """
150
    Get the `Account` object at an address. Returns `None` (rather than
151
    `EMPTY_ACCOUNT`) if there is no account at the address.
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
    """
166
    account = trie_get(state._main_trie, address)
167
    return account

get_code

Get the bytecode for a given code hash.

def get_code(state: State, ​​code_hash: Hash32) -> Bytes:
171
    """
172
    Get the bytecode for a given code hash.
173
    """
174
    if code_hash == EMPTY_CODE_HASH:
175
        return b""
176
    return state._code_store[code_hash]

store_code

Store bytecode in State.

def store_code(state: State, ​​code: Bytes) -> Hash32:
180
    """
181
    Store bytecode in ``State``.
182
    """
183
    code_hash = keccak256(code)
184
    if code_hash != EMPTY_CODE_HASH:
185
        state._code_store[code_hash] = code
186
    return code_hash

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:
192
    """
193
    Set the `Account` object at an address. Setting to `None` deletes
194
    the account (but not its storage, see `destroy_account()`).
195
196
    Parameters
197
    ----------
198
    state: `State`
199
        The state
200
    address : `Address`
201
        Address to set.
202
    account : `Account`
203
        Account to set at address.
204
205
    """
206
    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:
210
    """
211
    Completely remove the account at `address` and all of its storage.
212
213
    This function is made available exclusively for the `SELFDESTRUCT`
214
    opcode. It is expected that `SELFDESTRUCT` will be disabled in a future
215
    hardfork and this function will be removed.
216
217
    Parameters
218
    ----------
219
    state: `State`
220
        The state
221
    address : `Address`
222
        Address of account to destroy.
223
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
    """
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
    """
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
    """
286
    trie = state._storage_tries.get(address)
287
    if trie is None:
288
        return U256(0)
289
290
    value = trie_get(trie, key)
291
292
    assert isinstance(value, U256)
293
    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:
299
    """
300
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
301
    the key.
302
303
    Parameters
304
    ----------
305
    state: `State`
306
        The state
307
    address : `Address`
308
        Address of the account.
309
    key : `Bytes`
310
        Key to set.
311
    value : `U256`
312
        Value to set at the key.
313
314
    """
315
    assert trie_get(state._main_trie, address) is not None
316
317
    trie = state._storage_tries.get(address)
318
    if trie is None:
319
        trie = Trie(secured=True, default=U256(0))
320
        state._storage_tries[address] = trie
321
    trie_set(trie, key, value)
322
    if trie._data == {}:
323
        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:
327
    """
328
    Calculate the storage root of an account.
329
330
    Parameters
331
    ----------
332
    state:
333
        The state
334
    address :
335
        Address of the account.
336
337
    Returns
338
    -------
339
    root : `Root`
340
        Storage root of the account.
341
342
    """
343
    assert not state._snapshots
344
    if address in state._storage_tries:
345
        return root(state._storage_tries[address])
346
    else:
347
        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:
351
    """
352
    Calculate the state root.
353
354
    Parameters
355
    ----------
356
    state:
357
        The current state.
358
359
    Returns
360
    -------
361
    root : `Root`
362
        The state root.
363
364
    """
365
    assert not state._snapshots
366
367
    def get_storage_root(address: Address) -> Root:
368
        return storage_root(state, address)
369
370
    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:
374
    """
375
    Checks if an account exists in the state trie.
376
377
    Parameters
378
    ----------
379
    state:
380
        The state
381
    address:
382
        Address of the account that needs to be checked.
383
384
    Returns
385
    -------
386
    account_exists : `bool`
387
        True if account exists in the state trie, False otherwise
388
389
    """
390
    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:
394
    """
395
    Checks if an account has non-zero nonce or non-empty code.
396
397
    Parameters
398
    ----------
399
    state:
400
        The state
401
    address:
402
        Address of the account that needs to be checked.
403
404
    Returns
405
    -------
406
    has_code_or_nonce : `bool`
407
        True if the account has non-zero nonce or non-empty code,
408
        False otherwise.
409
410
    """
411
    account = get_account(state, address)
412
    return account.nonce != Uint(0) or account.code_hash != EMPTY_CODE_HASH

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:
416
    """
417
    Checks if an account has storage.
418
419
    Parameters
420
    ----------
421
    state:
422
        The state
423
    address:
424
        Address of the account that needs to be checked.
425
426
    Returns
427
    -------
428
    has_storage : `bool`
429
        True if the account has storage, False otherwise.
430
431
    """
432
    return address in state._storage_tries

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

is_account_alive

Check whether 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:
464
    """
465
    Check whether an account is both in the state and non-empty.
466
467
    Parameters
468
    ----------
469
    state:
470
        The state
471
    address:
472
        Address of the account that needs to be checked.
473
474
    Returns
475
    -------
476
    is_alive : `bool`
477
        True if the account is alive.
478
479
    """
480
    account = get_account_optional(state, address)
481
    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:
487
    """
488
    Modify an `Account` in the `State`.
489
    """
490
    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:
499
    """
500
    Move funds between accounts.
501
    """
502
503
    def reduce_sender_balance(sender: Account) -> None:
504
        if sender.balance < amount:
505
            raise AssertionError
506
        sender.balance -= amount
507
508
    def increase_recipient_balance(recipient: Account) -> None:
509
        recipient.balance += amount
510
511
    modify_state(state, sender_address, reduce_sender_balance)
512
    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 be set in the balance.

def set_account_balance(state: State, ​​address: Address, ​​amount: U256) -> None:
516
    """
517
    Sets the balance of an account.
518
519
    Parameters
520
    ----------
521
    state:
522
        The current state.
523
524
    address:
525
        Address of the account whose nonce needs to be incremented.
526
527
    amount:
528
        The amount that needs to be set in the balance.
529
530
    """
531
532
    def set_balance(account: Account) -> None:
533
        account.balance = amount
534
535
    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 needs to be initialized.

def touch_account(state: State, ​​address: Address) -> None:
539
    """
540
    Initializes an account to state.
541
542
    Parameters
543
    ----------
544
    state:
545
        The current state.
546
547
    address:
548
        The address of the account that needs to be initialized.
549
550
    """
551
    if not account_exists(state, address):
552
        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:
556
    """
557
    Increments the nonce of an account.
558
559
    Parameters
560
    ----------
561
    state:
562
        The current state.
563
564
    address:
565
        Address of the account whose nonce needs to be incremented.
566
567
    """
568
569
    def increase_nonce(sender: Account) -> None:
570
        sender.nonce += Uint(1)
571
572
    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 updated.

code: The bytecode that needs to be set.

def set_code(state: State, ​​address: Address, ​​code: Bytes) -> None:
576
    """
577
    Sets Account code.
578
579
    Parameters
580
    ----------
581
    state:
582
        The current state.
583
584
    address:
585
        Address of the account whose code needs to be updated.
586
587
    code:
588
        The bytecode that needs to be set.
589
590
    """
591
    code_hash = keccak256(code)
592
    if code_hash != EMPTY_CODE_HASH:
593
        state._code_store[code_hash] = code
594
595
    def write_code(sender: Account) -> None:
596
        sender.code_hash = code_hash
597
598
    modify_state(state, address, write_code)

create_ether

Add newly created ether to an account.

Parameters

state: The current state. address: Address of the account to which ether is added. amount: The amount of ether to be added to the account of interest.

def create_ether(state: State, ​​address: Address, ​​amount: U256) -> None:
602
    """
603
    Add newly created ether to an account.
604
605
    Parameters
606
    ----------
607
    state:
608
        The current state.
609
    address:
610
        Address of the account to which ether is added.
611
    amount:
612
        The amount of ether to be added to the account of interest.
613
614
    """
615
616
    def increase_balance(account: Account) -> None:
617
        account.balance += amount
618
619
    modify_state(state, address, increase_balance)

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:
623
    """
624
    Get the original value in a storage slot i.e. the value before the current
625
    transaction began. This function reads the value from the snapshots taken
626
    before executing the transaction.
627
628
    Parameters
629
    ----------
630
    state:
631
        The current state.
632
    address:
633
        Address of the account to read the value from.
634
    key:
635
        Key of the storage slot.
636
637
    """
638
    # In the transaction where an account is created, its preexisting storage
639
    # is ignored.
640
    if address in state.created_accounts:
641
        return U256(0)
642
643
    _, original_trie = state._snapshots[0]
644
    original_account_trie = original_trie.get(address)
645
646
    if original_account_trie is None:
647
        original_value = U256(0)
648
    else:
649
        original_value = trie_get(original_account_trie, key)
650
651
    assert isinstance(original_value, U256)
652
653
    return original_value

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:
659
    """
660
    Destroy all touched accounts that are empty.
661
662
    Parameters
663
    ----------
664
    state: `State`
665
        The current state.
666
    touched_accounts: `Iterable[Address]`
667
        All the accounts that have been touched in the current transaction.
668
669
    """
670
    for address in touched_accounts:
671
        if account_exists_and_is_empty(state, address):
672
            destroy_account(state, address)