ethereum.shanghai.fork

Ethereum Specification ^^^^^^^^^^^^^^^^^^^^^^

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Entry point for the Ethereum specification.

BASE_FEE_MAX_CHANGE_DENOMINATOR

59
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

60
ELASTICITY_MULTIPLIER = Uint(2)

GAS_LIMIT_ADJUSTMENT_FACTOR

61
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

62
GAS_LIMIT_MINIMUM = Uint(5000)

EMPTY_OMMER_HASH

63
EMPTY_OMMER_HASH = keccak256(rlp.encode([]))

BlockChain

History and current state of the block chain.

66
@dataclass
class BlockChain:

blocks

72
    blocks: List[Block]

state

73
    state: State

chain_id

74
    chain_id: U64

apply_fork

Transforms the state from the previous hard fork (old) into the block chain object for this hard fork and returns it.

When forks need to implement an irregular state transition, this function is used to handle the irregularity. See the :ref:DAO Fork <dao-fork> for an example.

Parameters

old : Previous block chain object.

Returns

new : BlockChain Upgraded block chain object for this hard fork.

def apply_fork(old: BlockChain) -> BlockChain:
78
    """
79
    Transforms the state from the previous hard fork (`old`) into the block
80
    chain object for this hard fork and returns it.
81
82
    When forks need to implement an irregular state transition, this function
83
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
84
    an example.
85
86
    Parameters
87
    ----------
88
    old :
89
        Previous block chain object.
90
91
    Returns
92
    -------
93
    new : `BlockChain`
94
        Upgraded block chain object for this hard fork.
95
    """
96
    return old

get_last_256_block_hashes

Obtain the list of hashes of the previous 256 blocks in order of increasing block number.

This function will return less hashes for the first 256 blocks.

The BLOCKHASH opcode needs to access the latest hashes on the chain, therefore this function retrieves them.

Parameters

chain : History and current state.

Returns

recent_block_hashes : List[Hash32] Hashes of the recent 256 blocks in order of increasing block number.

def get_last_256_block_hashes(chain: BlockChain) -> List[Hash32]:
100
    """
101
    Obtain the list of hashes of the previous 256 blocks in order of
102
    increasing block number.
103
104
    This function will return less hashes for the first 256 blocks.
105
106
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
107
    therefore this function retrieves them.
108
109
    Parameters
110
    ----------
111
    chain :
112
        History and current state.
113
114
    Returns
115
    -------
116
    recent_block_hashes : `List[Hash32]`
117
        Hashes of the recent 256 blocks in order of increasing block number.
118
    """
119
    recent_blocks = chain.blocks[-255:]
120
    # TODO: This function has not been tested rigorously
121
    if len(recent_blocks) == 0:
122
        return []
123
124
    recent_block_hashes = []
125
126
    for block in recent_blocks:
127
        prev_block_hash = block.header.parent_hash
128
        recent_block_hashes.append(prev_block_hash)
129
130
    # We are computing the hash only for the most recent block and not for
131
    # the rest of the blocks as they have successors which have the hash of
132
    # the current block as parent hash.
133
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
134
    recent_block_hashes.append(most_recent_block_hash)
135
136
    return recent_block_hashes

state_transition

Attempts to apply a block to an existing block chain.

All parts of the block's contents need to be verified before being added to the chain. Blocks are verified by ensuring that the contents of the block make logical sense with the contents of the parent block. The information in the block's header must also match the corresponding information in the block.

To implement Ethereum, in theory clients are only required to store the most recent 255 blocks of the chain since as far as execution is concerned, only those blocks are accessed. Practically, however, clients should store more blocks to handle reorgs.

Parameters

chain : History and current state. block : Block to apply to chain.

def state_transition(chain: BlockChain, ​​block: Block) -> None:
140
    """
141
    Attempts to apply a block to an existing block chain.
142
143
    All parts of the block's contents need to be verified before being added
144
    to the chain. Blocks are verified by ensuring that the contents of the
145
    block make logical sense with the contents of the parent block. The
146
    information in the block's header must also match the corresponding
147
    information in the block.
148
149
    To implement Ethereum, in theory clients are only required to store the
150
    most recent 255 blocks of the chain since as far as execution is
151
    concerned, only those blocks are accessed. Practically, however, clients
152
    should store more blocks to handle reorgs.
153
154
    Parameters
155
    ----------
156
    chain :
157
        History and current state.
158
    block :
159
        Block to apply to `chain`.
160
    """
161
    parent_header = chain.blocks[-1].header
162
    validate_header(block.header, parent_header)
163
    if block.ommers != ():
164
        raise InvalidBlock
165
    apply_body_output = apply_body(
166
        chain.state,
167
        get_last_256_block_hashes(chain),
168
        block.header.coinbase,
169
        block.header.number,
170
        block.header.base_fee_per_gas,
171
        block.header.gas_limit,
172
        block.header.timestamp,
173
        block.header.prev_randao,
174
        block.transactions,
175
        chain.chain_id,
176
        block.withdrawals,
177
    )
178
    if apply_body_output.block_gas_used != block.header.gas_used:
179
        raise InvalidBlock(
180
            f"{apply_body_output.block_gas_used} != {block.header.gas_used}"
181
        )
182
    if apply_body_output.transactions_root != block.header.transactions_root:
183
        raise InvalidBlock
184
    if apply_body_output.state_root != block.header.state_root:
185
        raise InvalidBlock
186
    if apply_body_output.receipt_root != block.header.receipt_root:
187
        raise InvalidBlock
188
    if apply_body_output.block_logs_bloom != block.header.bloom:
189
        raise InvalidBlock
190
    if apply_body_output.withdrawals_root != block.header.withdrawals_root:
191
        raise InvalidBlock
192
193
    chain.blocks.append(block)
194
    if len(chain.blocks) > 255:
195
        # Real clients have to store more blocks to deal with reorgs, but the
196
        # protocol only requires the last 255
197
        chain.blocks = chain.blocks[-255:]

calculate_base_fee_per_gas

Calculates the base fee per gas for the block.

Parameters

block_gas_limit : Gas limit of the block for which the base fee is being calculated. parent_gas_limit : Gas limit of the parent block. parent_gas_used : Gas used in the parent block. parent_base_fee_per_gas : Base fee per gas of the parent block.

Returns

base_fee_per_gas : Uint Base fee per gas for the block.

def calculate_base_fee_per_gas(block_gas_limit: Uint, ​​parent_gas_limit: Uint, ​​parent_gas_used: Uint, ​​parent_base_fee_per_gas: Uint) -> Uint:
206
    """
207
    Calculates the base fee per gas for the block.
208
209
    Parameters
210
    ----------
211
    block_gas_limit :
212
        Gas limit of the block for which the base fee is being calculated.
213
    parent_gas_limit :
214
        Gas limit of the parent block.
215
    parent_gas_used :
216
        Gas used in the parent block.
217
    parent_base_fee_per_gas :
218
        Base fee per gas of the parent block.
219
220
    Returns
221
    -------
222
    base_fee_per_gas : `Uint`
223
        Base fee per gas for the block.
224
    """
225
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
226
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
227
        raise InvalidBlock
228
229
    if parent_gas_used == parent_gas_target:
230
        expected_base_fee_per_gas = parent_base_fee_per_gas
231
    elif parent_gas_used > parent_gas_target:
232
        gas_used_delta = parent_gas_used - parent_gas_target
233
234
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
235
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
236
237
        base_fee_per_gas_delta = max(
238
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
239
            Uint(1),
240
        )
241
242
        expected_base_fee_per_gas = (
243
            parent_base_fee_per_gas + base_fee_per_gas_delta
244
        )
245
    else:
246
        gas_used_delta = parent_gas_target - parent_gas_used
247
248
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
249
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
250
251
        base_fee_per_gas_delta = (
252
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
253
        )
254
255
        expected_base_fee_per_gas = (
256
            parent_base_fee_per_gas - base_fee_per_gas_delta
257
        )
258
259
    return Uint(expected_base_fee_per_gas)

validate_header

Verifies a block header.

In order to consider a block's header valid, the logic for the quantities in the header should match the logic for the block itself. For example the header timestamp should be greater than the block's parent timestamp because the block was created after the parent block. Additionally, the block's number should be directly following the parent block's number since it is the next block in the sequence.

Parameters

header : Header to check for correctness. parent_header : Parent Header of the header to check for correctness

def validate_header(header: Header, ​​parent_header: Header) -> None:
263
    """
264
    Verifies a block header.
265
266
    In order to consider a block's header valid, the logic for the
267
    quantities in the header should match the logic for the block itself.
268
    For example the header timestamp should be greater than the block's parent
269
    timestamp because the block was created *after* the parent block.
270
    Additionally, the block's number should be directly following the parent
271
    block's number since it is the next block in the sequence.
272
273
    Parameters
274
    ----------
275
    header :
276
        Header to check for correctness.
277
    parent_header :
278
        Parent Header of the header to check for correctness
279
    """
280
    if header.gas_used > header.gas_limit:
281
        raise InvalidBlock
282
283
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
284
        header.gas_limit,
285
        parent_header.gas_limit,
286
        parent_header.gas_used,
287
        parent_header.base_fee_per_gas,
288
    )
289
    if expected_base_fee_per_gas != header.base_fee_per_gas:
290
        raise InvalidBlock
291
    if header.timestamp <= parent_header.timestamp:
292
        raise InvalidBlock
293
    if header.number != parent_header.number + Uint(1):
294
        raise InvalidBlock
295
    if len(header.extra_data) > 32:
296
        raise InvalidBlock
297
    if header.difficulty != 0:
298
        raise InvalidBlock
299
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
300
        raise InvalidBlock
301
    if header.ommers_hash != EMPTY_OMMER_HASH:
302
        raise InvalidBlock
303
304
    block_parent_hash = keccak256(rlp.encode(parent_header))
305
    if header.parent_hash != block_parent_hash:
306
        raise InvalidBlock

check_transaction

Check if the transaction is includable in the block.

Parameters

tx : The transaction. base_fee_per_gas : The block base fee. gas_available : The gas remaining in the block. chain_id : The ID of the current chain.

Returns

sender_address : The sender of the transaction. effective_gas_price : The price to charge for gas when the transaction is executed.

Raises

InvalidBlock : If the transaction is not includable.

def check_transaction(tx: Transaction, ​​base_fee_per_gas: Uint, ​​gas_available: Uint, ​​chain_id: U64) -> Tuple[Address, Uint]:
315
    """
316
    Check if the transaction is includable in the block.
317
318
    Parameters
319
    ----------
320
    tx :
321
        The transaction.
322
    base_fee_per_gas :
323
        The block base fee.
324
    gas_available :
325
        The gas remaining in the block.
326
    chain_id :
327
        The ID of the current chain.
328
329
    Returns
330
    -------
331
    sender_address :
332
        The sender of the transaction.
333
    effective_gas_price :
334
        The price to charge for gas when the transaction is executed.
335
336
    Raises
337
    ------
338
    InvalidBlock :
339
        If the transaction is not includable.
340
    """
341
    if tx.gas > gas_available:
342
        raise InvalidBlock
343
    sender_address = recover_sender(chain_id, tx)
344
345
    if isinstance(tx, FeeMarketTransaction):
346
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
347
            raise InvalidBlock
348
        if tx.max_fee_per_gas < base_fee_per_gas:
349
            raise InvalidBlock
350
351
        priority_fee_per_gas = min(
352
            tx.max_priority_fee_per_gas,
353
            tx.max_fee_per_gas - base_fee_per_gas,
354
        )
355
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
356
    else:
357
        if tx.gas_price < base_fee_per_gas:
358
            raise InvalidBlock
359
        effective_gas_price = tx.gas_price
360
361
    return sender_address, effective_gas_price

make_receipt

Make the receipt for a transaction that was executed.

Parameters

tx : The executed transaction. error : Error in the top level frame of the transaction, if any. cumulative_gas_used : The total gas used so far in the block after the transaction was executed. logs : The logs produced by the transaction.

Returns

receipt : The receipt for the transaction.

def make_receipt(tx: Transaction, ​​error: Optional[Exception], ​​cumulative_gas_used: Uint, ​​logs: Tuple[Log, ...]) -> Union[Bytes, Receipt]:
370
    """
371
    Make the receipt for a transaction that was executed.
372
373
    Parameters
374
    ----------
375
    tx :
376
        The executed transaction.
377
    error :
378
        Error in the top level frame of the transaction, if any.
379
    cumulative_gas_used :
380
        The total gas used so far in the block after the transaction was
381
        executed.
382
    logs :
383
        The logs produced by the transaction.
384
385
    Returns
386
    -------
387
    receipt :
388
        The receipt for the transaction.
389
    """
390
    receipt = Receipt(
391
        succeeded=error is None,
392
        cumulative_gas_used=cumulative_gas_used,
393
        bloom=logs_bloom(logs),
394
        logs=logs,
395
    )
396
397
    if isinstance(tx, AccessListTransaction):
398
        return b"\x01" + rlp.encode(receipt)
399
    elif isinstance(tx, FeeMarketTransaction):
400
        return b"\x02" + rlp.encode(receipt)
401
    else:
402
        return receipt

ApplyBodyOutput

Output from applying the block body to the present state.

Contains the following:

block_gas_used : ethereum.base_types.Uint Gas used for executing all transactions. transactions_root : ethereum.fork_types.Root Trie root of all the transactions in the block. receipt_root : ethereum.fork_types.Root Trie root of all the receipts in the block. block_logs_bloom : Bloom Logs bloom of all the logs included in all the transactions of the block. state_root : ethereum.fork_types.Root State root after all transactions have been executed. withdrawals_root : ethereum.fork_types.Root Trie root of all the withdrawals in the block.

405
@dataclass
class ApplyBodyOutput:

block_gas_used

427
    block_gas_used: Uint

transactions_root

428
    transactions_root: Root

receipt_root

429
    receipt_root: Root

block_logs_bloom

430
    block_logs_bloom: Bloom

state_root

431
    state_root: Root

withdrawals_root

432
    withdrawals_root: Root

apply_body

Executes a block.

Many of the contents of a block are stored in data structures called tries. There is a transactions trie which is similar to a ledger of the transactions stored in the current block. There is also a receipts trie which stores the results of executing a transaction, like the post state and gas used. This function creates and executes the block that is to be added to the chain.

Parameters

state : Current account state. block_hashes : List of hashes of the previous 256 blocks in the order of increasing block number. coinbase : Address of account which receives block reward and transaction fees. block_number : Position of the block within the chain. base_fee_per_gas : Base fee per gas of within the block. block_gas_limit : Initial amount of gas available for execution in this block. block_time : Time the block was produced, measured in seconds since the epoch. prev_randao : The previous randao from the beacon chain. transactions : Transactions included in the block. ommers : Headers of ancestor blocks which are not direct parents (formerly uncles.) chain_id : ID of the executing chain. withdrawals : Withdrawals to be processed in the current block.

Returns

apply_body_output : ApplyBodyOutput Output of applying the block body to the state.

def apply_body(state: State, ​​block_hashes: List[Hash32], ​​coinbase: Address, ​​block_number: Uint, ​​base_fee_per_gas: Uint, ​​block_gas_limit: Uint, ​​block_time: U256, ​​prev_randao: Bytes32, ​​transactions: Tuple[Union[LegacyTransaction, Bytes], ...], ​​chain_id: U64, ​​withdrawals: Tuple[Withdrawal, ...]) -> ApplyBodyOutput:
448
    """
449
    Executes a block.
450
451
    Many of the contents of a block are stored in data structures called
452
    tries. There is a transactions trie which is similar to a ledger of the
453
    transactions stored in the current block. There is also a receipts trie
454
    which stores the results of executing a transaction, like the post state
455
    and gas used. This function creates and executes the block that is to be
456
    added to the chain.
457
458
    Parameters
459
    ----------
460
    state :
461
        Current account state.
462
    block_hashes :
463
        List of hashes of the previous 256 blocks in the order of
464
        increasing block number.
465
    coinbase :
466
        Address of account which receives block reward and transaction fees.
467
    block_number :
468
        Position of the block within the chain.
469
    base_fee_per_gas :
470
        Base fee per gas of within the block.
471
    block_gas_limit :
472
        Initial amount of gas available for execution in this block.
473
    block_time :
474
        Time the block was produced, measured in seconds since the epoch.
475
    prev_randao :
476
        The previous randao from the beacon chain.
477
    transactions :
478
        Transactions included in the block.
479
    ommers :
480
        Headers of ancestor blocks which are not direct parents (formerly
481
        uncles.)
482
    chain_id :
483
        ID of the executing chain.
484
    withdrawals :
485
        Withdrawals to be processed in the current block.
486
487
    Returns
488
    -------
489
    apply_body_output : `ApplyBodyOutput`
490
        Output of applying the block body to the state.
491
    """
492
    gas_available = block_gas_limit
493
    transactions_trie: Trie[
494
        Bytes, Optional[Union[Bytes, LegacyTransaction]]
495
    ] = Trie(secured=False, default=None)
496
    receipts_trie: Trie[Bytes, Optional[Union[Bytes, Receipt]]] = Trie(
497
        secured=False, default=None
498
    )
499
    withdrawals_trie: Trie[Bytes, Optional[Union[Bytes, Withdrawal]]] = Trie(
500
        secured=False, default=None
501
    )
502
    block_logs: Tuple[Log, ...] = ()
503
504
    for i, tx in enumerate(map(decode_transaction, transactions)):
505
        trie_set(
506
            transactions_trie, rlp.encode(Uint(i)), encode_transaction(tx)
507
        )
508
509
        sender_address, effective_gas_price = check_transaction(
510
            tx, base_fee_per_gas, gas_available, chain_id
511
        )
512
513
        env = vm.Environment(
514
            caller=sender_address,
515
            origin=sender_address,
516
            block_hashes=block_hashes,
517
            coinbase=coinbase,
518
            number=block_number,
519
            gas_limit=block_gas_limit,
520
            base_fee_per_gas=base_fee_per_gas,
521
            gas_price=effective_gas_price,
522
            time=block_time,
523
            prev_randao=prev_randao,
524
            state=state,
525
            chain_id=chain_id,
526
            traces=[],
527
        )
528
529
        gas_used, logs, error = process_transaction(env, tx)
530
        gas_available -= gas_used
531
532
        receipt = make_receipt(
533
            tx, error, (block_gas_limit - gas_available), logs
534
        )
535
536
        trie_set(
537
            receipts_trie,
538
            rlp.encode(Uint(i)),
539
            receipt,
540
        )
541
542
        block_logs += logs
543
544
    block_gas_used = block_gas_limit - gas_available
545
546
    block_logs_bloom = logs_bloom(block_logs)
547
548
    for i, wd in enumerate(withdrawals):
549
        trie_set(withdrawals_trie, rlp.encode(Uint(i)), rlp.encode(wd))
550
551
        process_withdrawal(state, wd)
552
553
        if account_exists_and_is_empty(state, wd.address):
554
            destroy_account(state, wd.address)
555
556
    return ApplyBodyOutput(
557
        block_gas_used,
558
        root(transactions_trie),
559
        root(receipts_trie),
560
        block_logs_bloom,
561
        state_root(state),
562
        root(withdrawals_trie),
563
    )

process_transaction

Execute a transaction against the provided environment.

This function processes the actions needed to execute a transaction. It decrements the sender's account after calculating the gas fee and refunds them the proper amount after execution. Calling contracts, deploying code, and incrementing nonces are all examples of actions that happen within this function or from a call made within this function.

Accounts that are marked for deletion are processed and destroyed after execution.

Parameters

env : Environment for the Ethereum Virtual Machine. tx : Transaction to execute.

Returns

gas_left : ethereum.base_types.U256 Remaining gas after execution. logs : Tuple[ethereum.blocks.Log, ...] Logs generated during execution.

def process_transaction(env: ethereum.shanghai.vm.Environment, ​​tx: Transaction) -> Tuple[Uint, Tuple[Log, ...], Optional[Exception]]:
569
    """
570
    Execute a transaction against the provided environment.
571
572
    This function processes the actions needed to execute a transaction.
573
    It decrements the sender's account after calculating the gas fee and
574
    refunds them the proper amount after execution. Calling contracts,
575
    deploying code, and incrementing nonces are all examples of actions that
576
    happen within this function or from a call made within this function.
577
578
    Accounts that are marked for deletion are processed and destroyed after
579
    execution.
580
581
    Parameters
582
    ----------
583
    env :
584
        Environment for the Ethereum Virtual Machine.
585
    tx :
586
        Transaction to execute.
587
588
    Returns
589
    -------
590
    gas_left : `ethereum.base_types.U256`
591
        Remaining gas after execution.
592
    logs : `Tuple[ethereum.blocks.Log, ...]`
593
        Logs generated during execution.
594
    """
595
    if not validate_transaction(tx):
596
        raise InvalidBlock
597
598
    sender = env.origin
599
    sender_account = get_account(env.state, sender)
600
601
    if isinstance(tx, FeeMarketTransaction):
602
        max_gas_fee = tx.gas * tx.max_fee_per_gas
603
    else:
604
        max_gas_fee = tx.gas * tx.gas_price
605
    if sender_account.nonce != tx.nonce:
606
        raise InvalidBlock
607
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
608
        raise InvalidBlock
609
    if sender_account.code != bytearray():
610
        raise InvalidSenderError("not EOA")
611
612
    effective_gas_fee = tx.gas * env.gas_price
613
614
    gas = tx.gas - calculate_intrinsic_cost(tx)
615
    increment_nonce(env.state, sender)
616
617
    sender_balance_after_gas_fee = (
618
        Uint(sender_account.balance) - effective_gas_fee
619
    )
620
    set_account_balance(env.state, sender, U256(sender_balance_after_gas_fee))
621
622
    preaccessed_addresses = set()
623
    preaccessed_storage_keys = set()
624
    preaccessed_addresses.add(env.coinbase)
625
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
626
        for address, keys in tx.access_list:
627
            preaccessed_addresses.add(address)
628
            for key in keys:
629
                preaccessed_storage_keys.add((address, key))
630
631
    message = prepare_message(
632
        sender,
633
        tx.to,
634
        tx.value,
635
        tx.data,
636
        gas,
637
        env,
638
        preaccessed_addresses=frozenset(preaccessed_addresses),
639
        preaccessed_storage_keys=frozenset(preaccessed_storage_keys),
640
    )
641
642
    output = process_message_call(message, env)
643
644
    gas_used = tx.gas - output.gas_left
645
    gas_refund = min(gas_used // Uint(5), Uint(output.refund_counter))
646
    gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price
647
648
    # For non-1559 transactions env.gas_price == tx.gas_price
649
    priority_fee_per_gas = env.gas_price - env.base_fee_per_gas
650
    transaction_fee = (
651
        tx.gas - output.gas_left - gas_refund
652
    ) * priority_fee_per_gas
653
654
    total_gas_used = gas_used - gas_refund
655
656
    # refund gas
657
    sender_balance_after_refund = get_account(
658
        env.state, sender
659
    ).balance + U256(gas_refund_amount)
660
    set_account_balance(env.state, sender, sender_balance_after_refund)
661
662
    # transfer miner fees
663
    coinbase_balance_after_mining_fee = get_account(
664
        env.state, env.coinbase
665
    ).balance + U256(transaction_fee)
666
    if coinbase_balance_after_mining_fee != 0:
667
        set_account_balance(
668
            env.state, env.coinbase, coinbase_balance_after_mining_fee
669
        )
670
    elif account_exists_and_is_empty(env.state, env.coinbase):
671
        destroy_account(env.state, env.coinbase)
672
673
    for address in output.accounts_to_delete:
674
        destroy_account(env.state, address)
675
676
    for address in output.touched_accounts:
677
        if account_exists_and_is_empty(env.state, address):
678
            destroy_account(env.state, address)
679
680
    return total_gas_used, output.logs, output.error

validate_transaction

Verifies a transaction.

The gas in a transaction gets used to pay for the intrinsic cost of operations, therefore if there is insufficient gas then it would not be possible to execute a transaction and it will be declared invalid.

Additionally, the nonce of a transaction must not equal or exceed the limit defined in EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>_. In practice, defining the limit as 2**64-1 has no impact because sending 2**64-1 transactions is improbable. It's not strictly impossible though, 2**64-1 transactions is the entire capacity of the Ethereum blockchain at 2022 gas limits for a little over 22 years.

Parameters

tx : Transaction to validate.

Returns

verified : bool True if the transaction can be executed, or False otherwise.

def validate_transaction(tx: Transaction) -> bool:
684
    """
685
    Verifies a transaction.
686
687
    The gas in a transaction gets used to pay for the intrinsic cost of
688
    operations, therefore if there is insufficient gas then it would not
689
    be possible to execute a transaction and it will be declared invalid.
690
691
    Additionally, the nonce of a transaction must not equal or exceed the
692
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
693
    In practice, defining the limit as ``2**64-1`` has no impact because
694
    sending ``2**64-1`` transactions is improbable. It's not strictly
695
    impossible though, ``2**64-1`` transactions is the entire capacity of the
696
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
697
698
    Parameters
699
    ----------
700
    tx :
701
        Transaction to validate.
702
703
    Returns
704
    -------
705
    verified : `bool`
706
        True if the transaction can be executed, or False otherwise.
707
    """
708
    if calculate_intrinsic_cost(tx) > tx.gas:
709
        return False
710
    if tx.nonce >= U256(U64.MAX_VALUE):
711
        return False
712
    if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE:
713
        return False
714
715
    return True

calculate_intrinsic_cost

Calculates the gas that is charged before execution is started.

The intrinsic cost of the transaction is charged before execution has begun. Functions/operations in the EVM cost money to execute so this intrinsic cost is for the operations that need to be paid for as part of the transaction. Data transfer, for example, is part of this intrinsic cost. It costs ether to send data over the wire and that ether is accounted for in the intrinsic cost calculated in this function. This intrinsic cost must be calculated and paid for before execution in order for all operations to be implemented.

Parameters

tx : Transaction to compute the intrinsic cost of.

Returns

verified : ethereum.base_types.Uint The intrinsic cost of the transaction.

def calculate_intrinsic_cost(tx: Transaction) -> Uint:
719
    """
720
    Calculates the gas that is charged before execution is started.
721
722
    The intrinsic cost of the transaction is charged before execution has
723
    begun. Functions/operations in the EVM cost money to execute so this
724
    intrinsic cost is for the operations that need to be paid for as part of
725
    the transaction. Data transfer, for example, is part of this intrinsic
726
    cost. It costs ether to send data over the wire and that ether is
727
    accounted for in the intrinsic cost calculated in this function. This
728
    intrinsic cost must be calculated and paid for before execution in order
729
    for all operations to be implemented.
730
731
    Parameters
732
    ----------
733
    tx :
734
        Transaction to compute the intrinsic cost of.
735
736
    Returns
737
    -------
738
    verified : `ethereum.base_types.Uint`
739
        The intrinsic cost of the transaction.
740
    """
741
    data_cost = 0
742
743
    for byte in tx.data:
744
        if byte == 0:
745
            data_cost += TX_DATA_COST_PER_ZERO
746
        else:
747
            data_cost += TX_DATA_COST_PER_NON_ZERO
748
749
    if tx.to == Bytes0(b""):
750
        create_cost = TX_CREATE_COST + int(init_code_cost(Uint(len(tx.data))))
751
    else:
752
        create_cost = 0
753
754
    access_list_cost = 0
755
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
756
        for _address, keys in tx.access_list:
757
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
758
            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
759
760
    return Uint(TX_BASE_COST + data_cost + create_cost + access_list_cost)

recover_sender

Extracts the sender address from a transaction.

The v, r, and s values are the three parts that make up the signature of a transaction. In order to recover the sender of a transaction the two components needed are the signature (v, r, and s) and the signing hash of the transaction. The sender's public key can be obtained with these two values and therefore the sender address can be retrieved.

Parameters

tx : Transaction of interest. chain_id : ID of the executing chain.

Returns

sender : ethereum.fork_types.Address The address of the account that signed the transaction.

def recover_sender(chain_id: U64, ​​tx: Transaction) -> Address:
764
    """
765
    Extracts the sender address from a transaction.
766
767
    The v, r, and s values are the three parts that make up the signature
768
    of a transaction. In order to recover the sender of a transaction the two
769
    components needed are the signature (``v``, ``r``, and ``s``) and the
770
    signing hash of the transaction. The sender's public key can be obtained
771
    with these two values and therefore the sender address can be retrieved.
772
773
    Parameters
774
    ----------
775
    tx :
776
        Transaction of interest.
777
    chain_id :
778
        ID of the executing chain.
779
780
    Returns
781
    -------
782
    sender : `ethereum.fork_types.Address`
783
        The address of the account that signed the transaction.
784
    """
785
    r, s = tx.r, tx.s
786
    if U256(0) >= r or r >= SECP256K1N:
787
        raise InvalidBlock
788
    if U256(0) >= s or s > SECP256K1N // U256(2):
789
        raise InvalidBlock
790
791
    if isinstance(tx, LegacyTransaction):
792
        v = tx.v
793
        if v == 27 or v == 28:
794
            public_key = secp256k1_recover(
795
                r, s, v - U256(27), signing_hash_pre155(tx)
796
            )
797
        else:
798
            chain_id_x2 = U256(chain_id) * U256(2)
799
            if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
800
                raise InvalidBlock
801
            public_key = secp256k1_recover(
802
                r,
803
                s,
804
                v - U256(35) - chain_id_x2,
805
                signing_hash_155(tx, chain_id),
806
            )
807
    elif isinstance(tx, AccessListTransaction):
808
        public_key = secp256k1_recover(
809
            r, s, tx.y_parity, signing_hash_2930(tx)
810
        )
811
    elif isinstance(tx, FeeMarketTransaction):
812
        public_key = secp256k1_recover(
813
            r, s, tx.y_parity, signing_hash_1559(tx)
814
        )
815
816
    return Address(keccak256(public_key)[12:32])

signing_hash_pre155

Compute the hash of a transaction used in a legacy (pre EIP 155) signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_pre155(tx: LegacyTransaction) -> Hash32:
820
    """
821
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
822
823
    Parameters
824
    ----------
825
    tx :
826
        Transaction of interest.
827
828
    Returns
829
    -------
830
    hash : `ethereum.crypto.hash.Hash32`
831
        Hash of the transaction.
832
    """
833
    return keccak256(
834
        rlp.encode(
835
            (
836
                tx.nonce,
837
                tx.gas_price,
838
                tx.gas,
839
                tx.to,
840
                tx.value,
841
                tx.data,
842
            )
843
        )
844
    )

signing_hash_155

Compute the hash of a transaction used in a EIP 155 signature.

Parameters

tx : Transaction of interest. chain_id : The id of the current chain.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_155(tx: LegacyTransaction, ​​chain_id: U64) -> Hash32:
848
    """
849
    Compute the hash of a transaction used in a EIP 155 signature.
850
851
    Parameters
852
    ----------
853
    tx :
854
        Transaction of interest.
855
    chain_id :
856
        The id of the current chain.
857
858
    Returns
859
    -------
860
    hash : `ethereum.crypto.hash.Hash32`
861
        Hash of the transaction.
862
    """
863
    return keccak256(
864
        rlp.encode(
865
            (
866
                tx.nonce,
867
                tx.gas_price,
868
                tx.gas,
869
                tx.to,
870
                tx.value,
871
                tx.data,
872
                chain_id,
873
                Uint(0),
874
                Uint(0),
875
            )
876
        )
877
    )

signing_hash_2930

Compute the hash of a transaction used in a EIP 2930 signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_2930(tx: AccessListTransaction) -> Hash32:
881
    """
882
    Compute the hash of a transaction used in a EIP 2930 signature.
883
884
    Parameters
885
    ----------
886
    tx :
887
        Transaction of interest.
888
889
    Returns
890
    -------
891
    hash : `ethereum.crypto.hash.Hash32`
892
        Hash of the transaction.
893
    """
894
    return keccak256(
895
        b"\x01"
896
        + rlp.encode(
897
            (
898
                tx.chain_id,
899
                tx.nonce,
900
                tx.gas_price,
901
                tx.gas,
902
                tx.to,
903
                tx.value,
904
                tx.data,
905
                tx.access_list,
906
            )
907
        )
908
    )

signing_hash_1559

Compute the hash of a transaction used in a EIP 1559 signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_1559(tx: FeeMarketTransaction) -> Hash32:
912
    """
913
    Compute the hash of a transaction used in a EIP 1559 signature.
914
915
    Parameters
916
    ----------
917
    tx :
918
        Transaction of interest.
919
920
    Returns
921
    -------
922
    hash : `ethereum.crypto.hash.Hash32`
923
        Hash of the transaction.
924
    """
925
    return keccak256(
926
        b"\x02"
927
        + rlp.encode(
928
            (
929
                tx.chain_id,
930
                tx.nonce,
931
                tx.max_priority_fee_per_gas,
932
                tx.max_fee_per_gas,
933
                tx.gas,
934
                tx.to,
935
                tx.value,
936
                tx.data,
937
                tx.access_list,
938
            )
939
        )
940
    )

compute_header_hash

Computes the hash of a block header.

The header hash of a block is the canonical hash that is used to refer to a specific block and completely distinguishes a block from another.

keccak256 is a function that produces a 256 bit hash of any input. It also takes in any number of bytes as an input and produces a single hash for them. A hash is a completely unique output for a single input. So an input corresponds to one unique hash that can be used to identify the input exactly.

Prior to using the keccak256 hash function, the header must be encoded using the Recursive-Length Prefix. See :ref:rlp. RLP encoding the header converts it into a space-efficient format that allows for easy transfer of data between nodes. The purpose of RLP is to encode arbitrarily nested arrays of binary data, and RLP is the primary encoding method used to serialize objects in Ethereum's execution layer. The only purpose of RLP is to encode structure; encoding specific data types (e.g. strings, floats) is left up to higher-order protocols.

Parameters

header : Header of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the header.

def compute_header_hash(header: Header) -> Hash32:
944
    """
945
    Computes the hash of a block header.
946
947
    The header hash of a block is the canonical hash that is used to refer
948
    to a specific block and completely distinguishes a block from another.
949
950
    ``keccak256`` is a function that produces a 256 bit hash of any input.
951
    It also takes in any number of bytes as an input and produces a single
952
    hash for them. A hash is a completely unique output for a single input.
953
    So an input corresponds to one unique hash that can be used to identify
954
    the input exactly.
955
956
    Prior to using the ``keccak256`` hash function, the header must be
957
    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
958
    RLP encoding the header converts it into a space-efficient format that
959
    allows for easy transfer of data between nodes. The purpose of RLP is to
960
    encode arbitrarily nested arrays of binary data, and RLP is the primary
961
    encoding method used to serialize objects in Ethereum's execution layer.
962
    The only purpose of RLP is to encode structure; encoding specific data
963
    types (e.g. strings, floats) is left up to higher-order protocols.
964
965
    Parameters
966
    ----------
967
    header :
968
        Header of interest.
969
970
    Returns
971
    -------
972
    hash : `ethereum.crypto.hash.Hash32`
973
        Hash of the header.
974
    """
975
    return keccak256(rlp.encode(header))

check_gas_limit

Validates the gas limit for a block.

The bounds of the gas limit, max_adjustment_delta, is set as the quotient of the parent block's gas limit and the GAS_LIMIT_ADJUSTMENT_FACTOR. Therefore, if the gas limit that is passed through as a parameter is greater than or equal to the sum of the parent's gas and the adjustment delta then the limit for gas is too high and fails this function's check. Similarly, if the limit is less than or equal to the difference of the parent's gas and the adjustment delta or the predefined GAS_LIMIT_MINIMUM then this function's check fails because the gas limit doesn't allow for a sufficient or reasonable amount of gas to be used on a block.

Parameters

gas_limit : Gas limit to validate.

parent_gas_limit : Gas limit of the parent block.

Returns

check : bool True if gas limit constraints are satisfied, False otherwise.

def check_gas_limit(gas_limit: Uint, ​​parent_gas_limit: Uint) -> bool:
979
    """
980
    Validates the gas limit for a block.
981
982
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
983
    quotient of the parent block's gas limit and the
984
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
985
    passed through as a parameter is greater than or equal to the *sum* of
986
    the parent's gas and the adjustment delta then the limit for gas is too
987
    high and fails this function's check. Similarly, if the limit is less
988
    than or equal to the *difference* of the parent's gas and the adjustment
989
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
990
    check fails because the gas limit doesn't allow for a sufficient or
991
    reasonable amount of gas to be used on a block.
992
993
    Parameters
994
    ----------
995
    gas_limit :
996
        Gas limit to validate.
997
998
    parent_gas_limit :
999
        Gas limit of the parent block.
1000
1001
    Returns
1002
    -------
1003
    check : `bool`
1004
        True if gas limit constraints are satisfied, False otherwise.
1005
    """
1006
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
1007
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
1008
        return False
1009
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
1010
        return False
1011
    if gas_limit < GAS_LIMIT_MINIMUM:
1012
        return False
1013
1014
    return True