ethereum.arrow_glacier.stateethereum.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.

28
@dataclass
class State:

_main_trie

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

_storage_tries

37
    _storage_tries: Dict[Address, Trie[Bytes, U256]] = field(
38
        default_factory=dict
39
    )

_snapshots

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

created_accounts

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

commit_transaction

Commit a state transaction.

Parameters

state : State The state.

def commit_transaction(state: State) -> None:
80
    """
81
    Commit a state transaction.
82
83
    Parameters
84
    ----------
85
    state : State
86
        The state.
87
    """
88
    state._snapshots.pop()
89
    if not state._snapshots:
90
        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:
94
    """
95
    Rollback a state transaction, resetting the state to the point when the
96
    corresponding `start_transaction()` call was made.
97
98
    Parameters
99
    ----------
100
    state : State
101
        The state.
102
    """
103
    state._main_trie, state._storage_tries = state._snapshots.pop()
104
    if not state._snapshots:
105
        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:
109
    """
110
    Get the `Account` object at an address. Returns `EMPTY_ACCOUNT` if there
111
    is no account at the address.
112
113
    Use `get_account_optional()` if you care about the difference between a
114
    non-existent account and `EMPTY_ACCOUNT`.
115
116
    Parameters
117
    ----------
118
    state: `State`
119
        The state
120
    address : `Address`
121
        Address to lookup.
122
123
    Returns
124
    -------
125
    account : `Account`
126
        Account at address.
127
    """
128
    account = get_account_optional(state, address)
129
    if isinstance(account, Account):
130
        return account
131
    else:
132
        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]:
136
    """
137
    Get the `Account` object at an address. Returns `None` (rather than
138
    `EMPTY_ACCOUNT`) if there is no account at the address.
139
140
    Parameters
141
    ----------
142
    state: `State`
143
        The state
144
    address : `Address`
145
        Address to lookup.
146
147
    Returns
148
    -------
149
    account : `Account`
150
        Account at address.
151
    """
152
    account = trie_get(state._main_trie, address)
153
    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:
159
    """
160
    Set the `Account` object at an address. Setting to `None` deletes
161
    the account (but not its storage, see `destroy_account()`).
162
163
    Parameters
164
    ----------
165
    state: `State`
166
        The state
167
    address : `Address`
168
        Address to set.
169
    account : `Account`
170
        Account to set at address.
171
    """
172
    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:
176
    """
177
    Completely remove the account at `address` and all of its storage.
178
179
    This function is made available exclusively for the `SELFDESTRUCT`
180
    opcode. It is expected that `SELFDESTRUCT` will be disabled in a future
181
    hardfork and this function will be removed.
182
183
    Parameters
184
    ----------
185
    state: `State`
186
        The state
187
    address : `Address`
188
        Address of account to destroy.
189
    """
190
    destroy_storage(state, address)
191
    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:
195
    """
196
    Completely remove the storage at `address`.
197
198
    Parameters
199
    ----------
200
    state: `State`
201
        The state
202
    address : `Address`
203
        Address of account whose storage is to be deleted.
204
    """
205
    if address in state._storage_tries:
206
        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:
210
    """
211
    Mark an account as having been created in the current transaction.
212
    This information is used by `get_storage_original()` to handle an obscure
213
    edgecase.
214
215
    The marker is not removed even if the account creation reverts. Since the
216
    account cannot have had code prior to its creation and can't call
217
    `get_storage_original()`, this is harmless.
218
219
    Parameters
220
    ----------
221
    state: `State`
222
        The state
223
    address : `Address`
224
        Address of the account that has been created.
225
    """
226
    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:
230
    """
231
    Get a value at a storage key on an account. Returns `U256(0)` if the
232
    storage key has not been set previously.
233
234
    Parameters
235
    ----------
236
    state: `State`
237
        The state
238
    address : `Address`
239
        Address of the account.
240
    key : `Bytes`
241
        Key to lookup.
242
243
    Returns
244
    -------
245
    value : `U256`
246
        Value at the key.
247
    """
248
    trie = state._storage_tries.get(address)
249
    if trie is None:
250
        return U256(0)
251
252
    value = trie_get(trie, key)
253
254
    assert isinstance(value, U256)
255
    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:
261
    """
262
    Set a value at a storage key on an account. Setting to `U256(0)` deletes
263
    the key.
264
265
    Parameters
266
    ----------
267
    state: `State`
268
        The state
269
    address : `Address`
270
        Address of the account.
271
    key : `Bytes`
272
        Key to set.
273
    value : `U256`
274
        Value to set at the key.
275
    """
276
    assert trie_get(state._main_trie, address) is not None
277
278
    trie = state._storage_tries.get(address)
279
    if trie is None:
280
        trie = Trie(secured=True, default=U256(0))
281
        state._storage_tries[address] = trie
282
    trie_set(trie, key, value)
283
    if trie._data == {}:
284
        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:
288
    """
289
    Calculate the storage root of an account.
290
291
    Parameters
292
    ----------
293
    state:
294
        The state
295
    address :
296
        Address of the account.
297
298
    Returns
299
    -------
300
    root : `Root`
301
        Storage root of the account.
302
    """
303
    assert not state._snapshots
304
    if address in state._storage_tries:
305
        return root(state._storage_tries[address])
306
    else:
307
        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:
311
    """
312
    Calculate the state root.
313
314
    Parameters
315
    ----------
316
    state:
317
        The current state.
318
319
    Returns
320
    -------
321
    root : `Root`
322
        The state root.
323
    """
324
    assert not state._snapshots
325
326
    def get_storage_root(address: Address) -> Root:
327
        return storage_root(state, address)
328
329
    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:
333
    """
334
    Checks if an account exists in the state trie
335
336
    Parameters
337
    ----------
338
    state:
339
        The state
340
    address:
341
        Address of the account that needs to be checked.
342
343
    Returns
344
    -------
345
    account_exists : `bool`
346
        True if account exists in the state trie, False otherwise
347
    """
348
    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:
352
    """
353
    Checks if an account has non zero nonce or non empty code
354
355
    Parameters
356
    ----------
357
    state:
358
        The state
359
    address:
360
        Address of the account that needs to be checked.
361
362
    Returns
363
    -------
364
    has_code_or_nonce : `bool`
365
        True if if an account has non zero nonce or non empty code,
366
        False otherwise.
367
    """
368
    account = get_account(state, address)
369
    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:
373
    """
374
    Checks if an account has zero nonce, empty code and zero balance.
375
376
    Parameters
377
    ----------
378
    state:
379
        The state
380
    address:
381
        Address of the account that needs to be checked.
382
383
    Returns
384
    -------
385
    is_empty : `bool`
386
        True if if an account has zero nonce, empty code and zero balance,
387
        False otherwise.
388
    """
389
    account = get_account(state, address)
390
    return (
391
        account.nonce == Uint(0)
392
        and account.code == b""
393
        and account.balance == 0
394
    )

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

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

modify_state

Modify an Account in the State.

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