ethereum.shanghai.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)

close_state

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

def close_state(state: State) -> None:
53
    """
54
    Free resources held by the state. Used by optimized implementations to
55
    release file descriptors.
56
    """
57
    del state._main_trie
58
    del state._storage_tries
59
    del state._snapshots
60
    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:
64
    """
65
    Start a state transaction.
66
67
    Transactions are entirely implicit and can be nested. It is not possible to
68
    calculate the state root during a transaction.
69
70
    Parameters
71
    ----------
72
    state : State
73
        The state.
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
    state._snapshots.pop()
93
    if not state._snapshots:
94
        state.created_accounts.clear()

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.

def rollback_transaction(state: State) -> None:
98
    """
99
    Rollback a state transaction, resetting the state to the point when the
100
    corresponding `start_transaction()` call was made.
101
102
    Parameters
103
    ----------
104
    state : State
105
        The state.
106
    """
107
    state._main_trie, state._storage_tries = state._snapshots.pop()
108
    if not state._snapshots:
109
        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:
113
    """
114
    Get the `Account` object at an address. Returns `EMPTY_ACCOUNT` if there
115
    is no account at the address.
116
117
    Use `get_account_optional()` if you care about the difference between a
118
    non-existent account and `EMPTY_ACCOUNT`.
119
120
    Parameters
121
    ----------
122
    state: `State`
123
        The state
124
    address : `Address`
125
        Address to lookup.
126
127
    Returns
128
    -------
129
    account : `Account`
130
        Account at address.
131
    """
132
    account = get_account_optional(state, address)
133
    if isinstance(account, Account):
134
        return account
135
    else:
136
        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]:
140
    """
141
    Get the `Account` object at an address. Returns `None` (rather than
142
    `EMPTY_ACCOUNT`) if there is no account at the address.
143
144
    Parameters
145
    ----------
146
    state: `State`
147
        The state
148
    address : `Address`
149
        Address to lookup.
150
151
    Returns
152
    -------
153
    account : `Account`
154
        Account at address.
155
    """
156
    account = trie_get(state._main_trie, address)
157
    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:
163
    """
164
    Set the `Account` object at an address. Setting to `None` deletes
165
    the account (but not its storage, see `destroy_account()`).
166
167
    Parameters
168
    ----------
169
    state: `State`
170
        The state
171
    address : `Address`
172
        Address to set.
173
    account : `Account`
174
        Account to set at address.
175
    """
176
    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:
180
    """
181
    Completely remove the account at `address` and all of its storage.
182
183
    This function is made available exclusively for the `SELFDESTRUCT`
184
    opcode. It is expected that `SELFDESTRUCT` will be disabled in a future
185
    hardfork and this function will be removed.
186
187
    Parameters
188
    ----------
189
    state: `State`
190
        The state
191
    address : `Address`
192
        Address of account to destroy.
193
    """
194
    destroy_storage(state, address)
195
    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:
199
    """
200
    Completely remove the storage at `address`.
201
202
    Parameters
203
    ----------
204
    state: `State`
205
        The state
206
    address : `Address`
207
        Address of account whose storage is to be deleted.
208
    """
209
    if address in state._storage_tries:
210
        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:
214
    """
215
    Mark an account as having been created in the current transaction.
216
    This information is used by `get_storage_original()` to handle an obscure
217
    edgecase.
218
219
    The marker is not removed even if the account creation reverts. Since the
220
    account cannot have had code prior to its creation and can't call
221
    `get_storage_original()`, this is harmless.
222
223
    Parameters
224
    ----------
225
    state: `State`
226
        The state
227
    address : `Address`
228
        Address of the account that has been created.
229
    """
230
    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:
234
    """
235
    Get a value at a storage key on an account. Returns `U256(0)` if the
236
    storage key has not been set previously.
237
238
    Parameters
239
    ----------
240
    state: `State`
241
        The state
242
    address : `Address`
243
        Address of the account.
244
    key : `Bytes`
245
        Key to lookup.
246
247
    Returns
248
    -------
249
    value : `U256`
250
        Value at the key.
251
    """
252
    trie = state._storage_tries.get(address)
253
    if trie is None:
254
        return U256(0)
255
256
    value = trie_get(trie, key)
257
258
    assert isinstance(value, U256)
259
    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:
265
    """
266
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
267
    the key.
268
269
    Parameters
270
    ----------
271
    state: `State`
272
        The state
273
    address : `Address`
274
        Address of the account.
275
    key : `Bytes`
276
        Key to set.
277
    value : `U256`
278
        Value to set at the key.
279
    """
280
    assert trie_get(state._main_trie, address) is not None
281
282
    trie = state._storage_tries.get(address)
283
    if trie is None:
284
        trie = Trie(secured=True, default=U256(0))
285
        state._storage_tries[address] = trie
286
    trie_set(trie, key, value)
287
    if trie._data == {}:
288
        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:
292
    """
293
    Calculate the storage root of an account.
294
295
    Parameters
296
    ----------
297
    state:
298
        The state
299
    address :
300
        Address of the account.
301
302
    Returns
303
    -------
304
    root : `Root`
305
        Storage root of the account.
306
    """
307
    assert not state._snapshots
308
    if address in state._storage_tries:
309
        return root(state._storage_tries[address])
310
    else:
311
        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:
315
    """
316
    Calculate the state root.
317
318
    Parameters
319
    ----------
320
    state:
321
        The current state.
322
323
    Returns
324
    -------
325
    root : `Root`
326
        The state root.
327
    """
328
    assert not state._snapshots
329
330
    def get_storage_root(address: Address) -> Root:
331
        return storage_root(state, address)
332
333
    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:
337
    """
338
    Checks if an account exists in the state trie
339
340
    Parameters
341
    ----------
342
    state:
343
        The state
344
    address:
345
        Address of the account that needs to be checked.
346
347
    Returns
348
    -------
349
    account_exists : `bool`
350
        True if account exists in the state trie, False otherwise
351
    """
352
    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:
356
    """
357
    Checks if an account has non zero nonce or non empty code
358
359
    Parameters
360
    ----------
361
    state:
362
        The state
363
    address:
364
        Address of the account that needs to be checked.
365
366
    Returns
367
    -------
368
    has_code_or_nonce : `bool`
369
        True if the account has non zero nonce or non empty code,
370
        False otherwise.
371
    """
372
    account = get_account(state, address)
373
    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:
377
    """
378
    Checks if an account has storage.
379
380
    Parameters
381
    ----------
382
    state:
383
        The state
384
    address:
385
        Address of the account that needs to be checked.
386
387
    Returns
388
    -------
389
    has_storage : `bool`
390
        True if the account has storage, False otherwise.
391
    """
392
    return address in state._storage_tries

is_account_empty

Checks if an account has zero nonce, empty code and zero balance.

Parameters

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

Returns

is_empty : bool True if if an account has zero nonce, empty code and zero balance, False otherwise.

def is_account_empty(state: State, ​​address: Address) -> bool:
396
    """
397
    Checks if an account has zero nonce, empty code and zero balance.
398
399
    Parameters
400
    ----------
401
    state:
402
        The state
403
    address:
404
        Address of the account that needs to be checked.
405
406
    Returns
407
    -------
408
    is_empty : `bool`
409
        True if if an account has zero nonce, empty code and zero balance,
410
        False otherwise.
411
    """
412
    account = get_account(state, address)
413
    return (
414
        account.nonce == Uint(0)
415
        and account.code == b""
416
        and account.balance == 0
417
    )

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:
421
    """
422
    Checks if an account exists and has zero nonce, empty code and zero
423
    balance.
424
425
    Parameters
426
    ----------
427
    state:
428
        The state
429
    address:
430
        Address of the account that needs to be checked.
431
432
    Returns
433
    -------
434
    exists_and_is_empty : `bool`
435
        True if an account exists and has zero nonce, empty code and zero
436
        balance, False otherwise.
437
    """
438
    account = get_account_optional(state, address)
439
    return (
440
        account is not None
441
        and account.nonce == Uint(0)
442
        and account.code == b""
443
        and account.balance == 0
444
    )

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:
448
    """
449
    Check whether is an account is both in the state and non empty.
450
451
    Parameters
452
    ----------
453
    state:
454
        The state
455
    address:
456
        Address of the account that needs to be checked.
457
458
    Returns
459
    -------
460
    is_alive : `bool`
461
        True if the account is alive.
462
    """
463
    account = get_account_optional(state, address)
464
    if account is None:
465
        return False
466
    else:
467
        return not (
468
            account.nonce == Uint(0)
469
            and account.code == b""
470
            and account.balance == 0
471
        )

modify_state

Modify an Account in the State.

def modify_state(state: State, ​​address: Address, ​​f: Callable[[Account], None]) -> None:
477
    """
478
    Modify an `Account` in the `State`.
479
    """
480
    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:
489
    """
490
    Move funds between accounts.
491
    """
492
493
    def reduce_sender_balance(sender: Account) -> None:
494
        if sender.balance < amount:
495
            raise AssertionError
496
        sender.balance -= amount
497
498
    def increase_recipient_balance(recipient: Account) -> None:
499
        recipient.balance += amount
500
501
    modify_state(state, sender_address, reduce_sender_balance)
502
    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:
509
    """
510
    Increase the balance of the withdrawing account.
511
    """
512
513
    def increase_recipient_balance(recipient: Account) -> None:
514
        recipient.balance += wd.amount * U256(10**9)
515
516
    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:
520
    """
521
    Sets the balance of an account.
522
523
    Parameters
524
    ----------
525
    state:
526
        The current state.
527
528
    address:
529
        Address of the account whose nonce needs to be incremented.
530
531
    amount:
532
        The amount that needs to set in balance.
533
    """
534
535
    def set_balance(account: Account) -> None:
536
        account.balance = amount
537
538
    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:
542
    """
543
    Initializes an account to state.
544
545
    Parameters
546
    ----------
547
    state:
548
        The current state.
549
550
    address:
551
        The address of the account that need to initialised.
552
    """
553
    if not account_exists(state, address):
554
        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:
558
    """
559
    Increments the nonce of an account.
560
561
    Parameters
562
    ----------
563
    state:
564
        The current state.
565
566
    address:
567
        Address of the account whose nonce needs to be incremented.
568
    """
569
570
    def increase_nonce(sender: Account) -> None:
571
        sender.nonce += Uint(1)
572
573
    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:
577
    """
578
    Sets Account code.
579
580
    Parameters
581
    ----------
582
    state:
583
        The current state.
584
585
    address:
586
        Address of the account whose code needs to be update.
587
588
    code:
589
        The bytecode that needs to be set.
590
    """
591
592
    def write_code(sender: Account) -> None:
593
        sender.code = code
594
595
    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:
599
    """
600
    Get the original value in a storage slot i.e. the value before the current
601
    transaction began. This function reads the value from the snapshots taken
602
    before executing the transaction.
603
604
    Parameters
605
    ----------
606
    state:
607
        The current state.
608
    address:
609
        Address of the account to read the value from.
610
    key:
611
        Key of the storage slot.
612
    """
613
    # In the transaction where an account is created, its preexisting storage
614
    # is ignored.
615
    if address in state.created_accounts:
616
        return U256(0)
617
618
    _, original_trie = state._snapshots[0]
619
    original_account_trie = original_trie.get(address)
620
621
    if original_account_trie is None:
622
        original_value = U256(0)
623
    else:
624
        original_value = trie_get(original_account_trie, key)
625
626
    assert isinstance(original_value, U256)
627
628
    return original_value