ethereum.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[Bytes, U256]] = field(
40
        default_factory=dict
41
    )

_snapshots

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

created_accounts

47
    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:
51
    """
52
    Free resources held by the state. Used by optimized implementations to
53
    release file descriptors.
54
    """
55
    del state._main_trie
56
    del state._storage_tries
57
    del state._snapshots
58
    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:
62
    """
63
    Start a state transaction.
64
65
    Transactions are entirely implicit and can be nested. It is not possible to
66
    calculate the state root during a transaction.
67
68
    Parameters
69
    ----------
70
    state : State
71
        The state.
72
    """
73
    state._snapshots.append(
74
        (
75
            copy_trie(state._main_trie),
76
            {k: copy_trie(t) for (k, t) in state._storage_tries.items()},
77
        )
78
    )

commit_transaction

Commit a state transaction.

Parameters

state : State The state.

def commit_transaction(state: State) -> None:
82
    """
83
    Commit a state transaction.
84
85
    Parameters
86
    ----------
87
    state : State
88
        The state.
89
    """
90
    state._snapshots.pop()
91
    if not state._snapshots:
92
        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:
96
    """
97
    Rollback a state transaction, resetting the state to the point when the
98
    corresponding `start_transaction()` call was made.
99
100
    Parameters
101
    ----------
102
    state : State
103
        The state.
104
    """
105
    state._main_trie, state._storage_tries = state._snapshots.pop()
106
    if not state._snapshots:
107
        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:
111
    """
112
    Get the `Account` object at an address. Returns `EMPTY_ACCOUNT` if there
113
    is no account at the address.
114
115
    Use `get_account_optional()` if you care about the difference between a
116
    non-existent account and `EMPTY_ACCOUNT`.
117
118
    Parameters
119
    ----------
120
    state: `State`
121
        The state
122
    address : `Address`
123
        Address to lookup.
124
125
    Returns
126
    -------
127
    account : `Account`
128
        Account at address.
129
    """
130
    account = get_account_optional(state, address)
131
    if isinstance(account, Account):
132
        return account
133
    else:
134
        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]:
138
    """
139
    Get the `Account` object at an address. Returns `None` (rather than
140
    `EMPTY_ACCOUNT`) if there is no account at the address.
141
142
    Parameters
143
    ----------
144
    state: `State`
145
        The state
146
    address : `Address`
147
        Address to lookup.
148
149
    Returns
150
    -------
151
    account : `Account`
152
        Account at address.
153
    """
154
    account = trie_get(state._main_trie, address)
155
    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:
161
    """
162
    Set the `Account` object at an address. Setting to `None` deletes
163
    the account (but not its storage, see `destroy_account()`).
164
165
    Parameters
166
    ----------
167
    state: `State`
168
        The state
169
    address : `Address`
170
        Address to set.
171
    account : `Account`
172
        Account to set at address.
173
    """
174
    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:
178
    """
179
    Completely remove the account at `address` and all of its storage.
180
181
    This function is made available exclusively for the `SELFDESTRUCT`
182
    opcode. It is expected that `SELFDESTRUCT` will be disabled in a future
183
    hardfork and this function will be removed.
184
185
    Parameters
186
    ----------
187
    state: `State`
188
        The state
189
    address : `Address`
190
        Address of account to destroy.
191
    """
192
    destroy_storage(state, address)
193
    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:
197
    """
198
    Completely remove the storage at `address`.
199
200
    Parameters
201
    ----------
202
    state: `State`
203
        The state
204
    address : `Address`
205
        Address of account whose storage is to be deleted.
206
    """
207
    if address in state._storage_tries:
208
        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:
212
    """
213
    Mark an account as having been created in the current transaction.
214
    This information is used by `get_storage_original()` to handle an obscure
215
    edgecase.
216
217
    The marker is not removed even if the account creation reverts. Since the
218
    account cannot have had code prior to its creation and can't call
219
    `get_storage_original()`, this is harmless.
220
221
    Parameters
222
    ----------
223
    state: `State`
224
        The state
225
    address : `Address`
226
        Address of the account that has been created.
227
    """
228
    state.created_accounts.add(address)

get_storage

Get a value at a storage key on an account. Returns U256(0) if the storage key has not been set previously.

Parameters

state: State The state address : Address Address of the account. key : Bytes Key to lookup.

Returns

value : U256 Value at the key.

def get_storage(state: State, ​​address: Address, ​​key: Bytes) -> U256:
232
    """
233
    Get a value at a storage key on an account. Returns `U256(0)` if the
234
    storage key has not been set previously.
235
236
    Parameters
237
    ----------
238
    state: `State`
239
        The state
240
    address : `Address`
241
        Address of the account.
242
    key : `Bytes`
243
        Key to lookup.
244
245
    Returns
246
    -------
247
    value : `U256`
248
        Value at the key.
249
    """
250
    trie = state._storage_tries.get(address)
251
    if trie is None:
252
        return U256(0)
253
254
    value = trie_get(trie, key)
255
256
    assert isinstance(value, U256)
257
    return value

set_storage

Set a value at a storage key on an account. Setting to U256(0) deletes the key.

Parameters

state: State The state address : Address Address of the account. key : Bytes Key to set. value : U256 Value to set at the key.

def set_storage(state: State, ​​address: Address, ​​key: Bytes, ​​value: U256) -> None:
263
    """
264
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
265
    the key.
266
267
    Parameters
268
    ----------
269
    state: `State`
270
        The state
271
    address : `Address`
272
        Address of the account.
273
    key : `Bytes`
274
        Key to set.
275
    value : `U256`
276
        Value to set at the key.
277
    """
278
    assert trie_get(state._main_trie, address) is not None
279
280
    trie = state._storage_tries.get(address)
281
    if trie is None:
282
        trie = Trie(secured=True, default=U256(0))
283
        state._storage_tries[address] = trie
284
    trie_set(trie, key, value)
285
    if trie._data == {}:
286
        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:
290
    """
291
    Calculate the storage root of an account.
292
293
    Parameters
294
    ----------
295
    state:
296
        The state
297
    address :
298
        Address of the account.
299
300
    Returns
301
    -------
302
    root : `Root`
303
        Storage root of the account.
304
    """
305
    assert not state._snapshots
306
    if address in state._storage_tries:
307
        return root(state._storage_tries[address])
308
    else:
309
        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:
313
    """
314
    Calculate the state root.
315
316
    Parameters
317
    ----------
318
    state:
319
        The current state.
320
321
    Returns
322
    -------
323
    root : `Root`
324
        The state root.
325
    """
326
    assert not state._snapshots
327
328
    def get_storage_root(address: Address) -> Root:
329
        return storage_root(state, address)
330
331
    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:
335
    """
336
    Checks if an account exists in the state trie
337
338
    Parameters
339
    ----------
340
    state:
341
        The state
342
    address:
343
        Address of the account that needs to be checked.
344
345
    Returns
346
    -------
347
    account_exists : `bool`
348
        True if account exists in the state trie, False otherwise
349
    """
350
    return get_account_optional(state, address) is not None

account_has_code_or_nonce

Checks if an account has non zero nonce or non empty code

Parameters

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

Returns

has_code_or_nonce : bool True if if an account has non zero nonce or non empty code, False otherwise.

def account_has_code_or_nonce(state: State, ​​address: Address) -> bool:
354
    """
355
    Checks if an account has non zero nonce or non empty code
356
357
    Parameters
358
    ----------
359
    state:
360
        The state
361
    address:
362
        Address of the account that needs to be checked.
363
364
    Returns
365
    -------
366
    has_code_or_nonce : `bool`
367
        True if if an account has non zero nonce or non empty code,
368
        False otherwise.
369
    """
370
    account = get_account(state, address)
371
    return account.nonce != Uint(0) or account.code != b""

is_account_empty

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

Parameters

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

Returns

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

def is_account_empty(state: State, ​​address: Address) -> bool:
375
    """
376
    Checks if an account has zero nonce, empty code and zero balance.
377
378
    Parameters
379
    ----------
380
    state:
381
        The state
382
    address:
383
        Address of the account that needs to be checked.
384
385
    Returns
386
    -------
387
    is_empty : `bool`
388
        True if if an account has zero nonce, empty code and zero balance,
389
        False otherwise.
390
    """
391
    account = get_account(state, address)
392
    return (
393
        account.nonce == Uint(0)
394
        and account.code == b""
395
        and account.balance == 0
396
    )

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:
400
    """
401
    Checks if an account exists and has zero nonce, empty code and zero
402
    balance.
403
404
    Parameters
405
    ----------
406
    state:
407
        The state
408
    address:
409
        Address of the account that needs to be checked.
410
411
    Returns
412
    -------
413
    exists_and_is_empty : `bool`
414
        True if an account exists and has zero nonce, empty code and zero
415
        balance, False otherwise.
416
    """
417
    account = get_account_optional(state, address)
418
    return (
419
        account is not None
420
        and account.nonce == Uint(0)
421
        and account.code == b""
422
        and account.balance == 0
423
    )

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:
427
    """
428
    Check whether is an account is both in the state and non empty.
429
430
    Parameters
431
    ----------
432
    state:
433
        The state
434
    address:
435
        Address of the account that needs to be checked.
436
437
    Returns
438
    -------
439
    is_alive : `bool`
440
        True if the account is alive.
441
    """
442
    account = get_account_optional(state, address)
443
    if account is None:
444
        return False
445
    else:
446
        return not (
447
            account.nonce == Uint(0)
448
            and account.code == b""
449
            and account.balance == 0
450
        )

modify_state

Modify an Account in the State.

def modify_state(state: State, ​​address: Address, ​​f: Callable[[Account], None]) -> None:
456
    """
457
    Modify an `Account` in the `State`.
458
    """
459
    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:
468
    """
469
    Move funds between accounts.
470
    """
471
472
    def reduce_sender_balance(sender: Account) -> None:
473
        if sender.balance < amount:
474
            raise AssertionError
475
        sender.balance -= amount
476
477
    def increase_recipient_balance(recipient: Account) -> None:
478
        recipient.balance += amount
479
480
    modify_state(state, sender_address, reduce_sender_balance)
481
    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:
485
    """
486
    Sets the balance of an account.
487
488
    Parameters
489
    ----------
490
    state:
491
        The current state.
492
493
    address:
494
        Address of the account whose nonce needs to be incremented.
495
496
    amount:
497
        The amount that needs to set in balance.
498
    """
499
500
    def set_balance(account: Account) -> None:
501
        account.balance = amount
502
503
    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:
507
    """
508
    Initializes an account to state.
509
510
    Parameters
511
    ----------
512
    state:
513
        The current state.
514
515
    address:
516
        The address of the account that need to initialised.
517
    """
518
    if not account_exists(state, address):
519
        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:
523
    """
524
    Increments the nonce of an account.
525
526
    Parameters
527
    ----------
528
    state:
529
        The current state.
530
531
    address:
532
        Address of the account whose nonce needs to be incremented.
533
    """
534
535
    def increase_nonce(sender: Account) -> None:
536
        sender.nonce += Uint(1)
537
538
    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:
542
    """
543
    Sets Account code.
544
545
    Parameters
546
    ----------
547
    state:
548
        The current state.
549
550
    address:
551
        Address of the account whose code needs to be update.
552
553
    code:
554
        The bytecode that needs to be set.
555
    """
556
557
    def write_code(sender: Account) -> None:
558
        sender.code = code
559
560
    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:
564
    """
565
    Add newly created ether to an account.
566
567
    Parameters
568
    ----------
569
    state:
570
        The current state.
571
    address:
572
        Address of the account to which ether is added.
573
    amount:
574
        The amount of ether to be added to the account of interest.
575
    """
576
577
    def increase_balance(account: Account) -> None:
578
        account.balance += amount
579
580
    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: Bytes) -> U256:
584
    """
585
    Get the original value in a storage slot i.e. the value before the current
586
    transaction began. This function reads the value from the snapshots taken
587
    before executing the transaction.
588
589
    Parameters
590
    ----------
591
    state:
592
        The current state.
593
    address:
594
        Address of the account to read the value from.
595
    key:
596
        Key of the storage slot.
597
    """
598
    # In the transaction where an account is created, its preexisting storage
599
    # is ignored.
600
    if address in state.created_accounts:
601
        return U256(0)
602
603
    _, original_trie = state._snapshots[0]
604
    original_account_trie = original_trie.get(address)
605
606
    if original_account_trie is None:
607
        original_value = U256(0)
608
    else:
609
        original_value = trie_get(original_account_trie, key)
610
611
    assert isinstance(original_value, U256)
612
613
    return original_value