ethereum.forks.istanbul.stateethereum.forks.muir_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.

30
@dataclass
class State:

_main_trie

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

_storage_tries

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

_snapshots

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

created_accounts

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

close_state

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

def close_state(state: State) -> None:
52
    """
53
    Free resources held by the state. Used by optimized implementations to
54
    release file descriptors.
55
    """
56
    del state._main_trie
57
    del state._storage_tries
58
    del state._snapshots
59
    del state.created_accounts

begin_transaction

Start a state transaction.

Transactions are entirely implicit and can be nested. It is not possible to calculate the state root during a transaction.

Parameters

state : State The state.

def begin_transaction(state: State) -> None:
63
    """
64
    Start a state transaction.
65
66
    Transactions are entirely implicit and can be nested. It is not possible to
67
    calculate the state root during a transaction.
68
69
    Parameters
70
    ----------
71
    state : State
72
        The state.
73
74
    """
75
    state._snapshots.append(
76
        (
77
            copy_trie(state._main_trie),
78
            {k: copy_trie(t) for (k, t) in state._storage_tries.items()},
79
        )
80
    )

commit_transaction

Commit a state transaction.

Parameters

state : State The state.

def commit_transaction(state: State) -> None:
84
    """
85
    Commit a state transaction.
86
87
    Parameters
88
    ----------
89
    state : State
90
        The state.
91
92
    """
93
    state._snapshots.pop()
94
    if not state._snapshots:
95
        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:
99
    """
100
    Rollback a state transaction, resetting the state to the point when the
101
    corresponding `begin_transaction()` call was made.
102
103
    Parameters
104
    ----------
105
    state : State
106
        The state.
107
108
    """
109
    state._main_trie, state._storage_tries = state._snapshots.pop()
110
    if not state._snapshots:
111
        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:
115
    """
116
    Get the `Account` object at an address. Returns `EMPTY_ACCOUNT` if there
117
    is no account at the address.
118
119
    Use `get_account_optional()` if you care about the difference between a
120
    non-existent account and `EMPTY_ACCOUNT`.
121
122
    Parameters
123
    ----------
124
    state: `State`
125
        The state
126
    address : `Address`
127
        Address to lookup.
128
129
    Returns
130
    -------
131
    account : `Account`
132
        Account at address.
133
134
    """
135
    account = get_account_optional(state, address)
136
    if isinstance(account, Account):
137
        return account
138
    else:
139
        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]:
143
    """
144
    Get the `Account` object at an address. Returns `None` (rather than
145
    `EMPTY_ACCOUNT`) if there is no account at the address.
146
147
    Parameters
148
    ----------
149
    state: `State`
150
        The state
151
    address : `Address`
152
        Address to lookup.
153
154
    Returns
155
    -------
156
    account : `Account`
157
        Account at address.
158
159
    """
160
    account = trie_get(state._main_trie, address)
161
    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:
167
    """
168
    Set the `Account` object at an address. Setting to `None` deletes
169
    the account (but not its storage, see `destroy_account()`).
170
171
    Parameters
172
    ----------
173
    state: `State`
174
        The state
175
    address : `Address`
176
        Address to set.
177
    account : `Account`
178
        Account to set at address.
179
180
    """
181
    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:
185
    """
186
    Completely remove the account at `address` and all of its storage.
187
188
    This function is made available exclusively for the `SELFDESTRUCT`
189
    opcode. It is expected that `SELFDESTRUCT` will be disabled in a future
190
    hardfork and this function will be removed.
191
192
    Parameters
193
    ----------
194
    state: `State`
195
        The state
196
    address : `Address`
197
        Address of account to destroy.
198
199
    """
200
    destroy_storage(state, address)
201
    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:
205
    """
206
    Completely remove the storage at `address`.
207
208
    Parameters
209
    ----------
210
    state: `State`
211
        The state
212
    address : `Address`
213
        Address of account whose storage is to be deleted.
214
215
    """
216
    if address in state._storage_tries:
217
        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:
221
    """
222
    Mark an account as having been created in the current transaction.
223
    This information is used by `get_storage_original()` to handle an obscure
224
    edgecase.
225
226
    The marker is not removed even if the account creation reverts. Since the
227
    account cannot have had code prior to its creation and can't call
228
    `get_storage_original()`, this is harmless.
229
230
    Parameters
231
    ----------
232
    state: `State`
233
        The state
234
    address : `Address`
235
        Address of the account that has been created.
236
237
    """
238
    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:
242
    """
243
    Get a value at a storage key on an account. Returns `U256(0)` if the
244
    storage key has not been set previously.
245
246
    Parameters
247
    ----------
248
    state: `State`
249
        The state
250
    address : `Address`
251
        Address of the account.
252
    key : `Bytes`
253
        Key to lookup.
254
255
    Returns
256
    -------
257
    value : `U256`
258
        Value at the key.
259
260
    """
261
    trie = state._storage_tries.get(address)
262
    if trie is None:
263
        return U256(0)
264
265
    value = trie_get(trie, key)
266
267
    assert isinstance(value, U256)
268
    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:
274
    """
275
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
276
    the key.
277
278
    Parameters
279
    ----------
280
    state: `State`
281
        The state
282
    address : `Address`
283
        Address of the account.
284
    key : `Bytes`
285
        Key to set.
286
    value : `U256`
287
        Value to set at the key.
288
289
    """
290
    assert trie_get(state._main_trie, address) is not None
291
292
    trie = state._storage_tries.get(address)
293
    if trie is None:
294
        trie = Trie(secured=True, default=U256(0))
295
        state._storage_tries[address] = trie
296
    trie_set(trie, key, value)
297
    if trie._data == {}:
298
        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:
302
    """
303
    Calculate the storage root of an account.
304
305
    Parameters
306
    ----------
307
    state:
308
        The state
309
    address :
310
        Address of the account.
311
312
    Returns
313
    -------
314
    root : `Root`
315
        Storage root of the account.
316
317
    """
318
    assert not state._snapshots
319
    if address in state._storage_tries:
320
        return root(state._storage_tries[address])
321
    else:
322
        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:
326
    """
327
    Calculate the state root.
328
329
    Parameters
330
    ----------
331
    state:
332
        The current state.
333
334
    Returns
335
    -------
336
    root : `Root`
337
        The state root.
338
339
    """
340
    assert not state._snapshots
341
342
    def get_storage_root(address: Address) -> Root:
343
        return storage_root(state, address)
344
345
    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:
349
    """
350
    Checks if an account exists in the state trie.
351
352
    Parameters
353
    ----------
354
    state:
355
        The state
356
    address:
357
        Address of the account that needs to be checked.
358
359
    Returns
360
    -------
361
    account_exists : `bool`
362
        True if account exists in the state trie, False otherwise
363
364
    """
365
    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:
369
    """
370
    Checks if an account has non zero nonce or non empty code.
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
    has_code_or_nonce : `bool`
382
        True if the account has non zero nonce or non empty code,
383
        False otherwise.
384
385
    """
386
    account = get_account(state, address)
387
    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:
391
    """
392
    Checks if an account has storage.
393
394
    Parameters
395
    ----------
396
    state:
397
        The state
398
    address:
399
        Address of the account that needs to be checked.
400
401
    Returns
402
    -------
403
    has_storage : `bool`
404
        True if the account has storage, False otherwise.
405
406
    """
407
    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:
411
    """
412
    Checks if an account exists and has zero nonce, empty code and zero
413
    balance.
414
415
    Parameters
416
    ----------
417
    state:
418
        The state
419
    address:
420
        Address of the account that needs to be checked.
421
422
    Returns
423
    -------
424
    exists_and_is_empty : `bool`
425
        True if an account exists and has zero nonce, empty code and zero
426
        balance, False otherwise.
427
428
    """
429
    account = get_account_optional(state, address)
430
    return (
431
        account is not None
432
        and account.nonce == Uint(0)
433
        and account.code == b""
434
        and account.balance == 0
435
    )

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:
439
    """
440
    Check whether an account is both in the state and non-empty.
441
442
    Parameters
443
    ----------
444
    state:
445
        The state
446
    address:
447
        Address of the account that needs to be checked.
448
449
    Returns
450
    -------
451
    is_alive : `bool`
452
        True if the account is alive.
453
454
    """
455
    account = get_account_optional(state, address)
456
    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:
462
    """
463
    Modify an `Account` in the `State`.
464
    """
465
    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:
474
    """
475
    Move funds between accounts.
476
    """
477
478
    def reduce_sender_balance(sender: Account) -> None:
479
        if sender.balance < amount:
480
            raise AssertionError
481
        sender.balance -= amount
482
483
    def increase_recipient_balance(recipient: Account) -> None:
484
        recipient.balance += amount
485
486
    modify_state(state, sender_address, reduce_sender_balance)
487
    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:
491
    """
492
    Sets the balance of an account.
493
494
    Parameters
495
    ----------
496
    state:
497
        The current state.
498
499
    address:
500
        Address of the account whose nonce needs to be incremented.
501
502
    amount:
503
        The amount that needs to set in balance.
504
505
    """
506
507
    def set_balance(account: Account) -> None:
508
        account.balance = amount
509
510
    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:
514
    """
515
    Initializes an account to state.
516
517
    Parameters
518
    ----------
519
    state:
520
        The current state.
521
522
    address:
523
        The address of the account that need to initialised.
524
525
    """
526
    if not account_exists(state, address):
527
        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:
531
    """
532
    Increments the nonce of an account.
533
534
    Parameters
535
    ----------
536
    state:
537
        The current state.
538
539
    address:
540
        Address of the account whose nonce needs to be incremented.
541
542
    """
543
544
    def increase_nonce(sender: Account) -> None:
545
        sender.nonce += Uint(1)
546
547
    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:
551
    """
552
    Sets Account code.
553
554
    Parameters
555
    ----------
556
    state:
557
        The current state.
558
559
    address:
560
        Address of the account whose code needs to be update.
561
562
    code:
563
        The bytecode that needs to be set.
564
565
    """
566
567
    def write_code(sender: Account) -> None:
568
        sender.code = code
569
570
    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:
574
    """
575
    Add newly created ether to an account.
576
577
    Parameters
578
    ----------
579
    state:
580
        The current state.
581
    address:
582
        Address of the account to which ether is added.
583
    amount:
584
        The amount of ether to be added to the account of interest.
585
586
    """
587
588
    def increase_balance(account: Account) -> None:
589
        account.balance += amount
590
591
    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:
595
    """
596
    Get the original value in a storage slot i.e. the value before the current
597
    transaction began. This function reads the value from the snapshots taken
598
    before executing the transaction.
599
600
    Parameters
601
    ----------
602
    state:
603
        The current state.
604
    address:
605
        Address of the account to read the value from.
606
    key:
607
        Key of the storage slot.
608
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

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:
631
    """
632
    Destroy all touched accounts that are empty.
633
634
    Parameters
635
    ----------
636
    state: `State`
637
        The current state.
638
    touched_accounts: `Iterable[Address]`
639
        All the accounts that have been touched in the current transaction.
640
641
    """
642
    for address in touched_accounts:
643
        if account_exists_and_is_empty(state, address):
644
            destroy_account(state, address)