ethereum.cancun.fork

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

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

Introduction

Entry point for the Ethereum specification.

BASE_FEE_MAX_CHANGE_DENOMINATOR

69
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

70
ELASTICITY_MULTIPLIER = Uint(2)

GAS_LIMIT_ADJUSTMENT_FACTOR

71
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

72
GAS_LIMIT_MINIMUM = Uint(5000)

EMPTY_OMMER_HASH

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

SYSTEM_ADDRESS

74
SYSTEM_ADDRESS = hex_to_address("0xfffffffffffffffffffffffffffffffffffffffe")

BEACON_ROOTS_ADDRESS

75
BEACON_ROOTS_ADDRESS = hex_to_address(
76
    "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"
77
)

SYSTEM_TRANSACTION_GAS

78
SYSTEM_TRANSACTION_GAS = Uint(30000000)

MAX_BLOB_GAS_PER_BLOCK

79
MAX_BLOB_GAS_PER_BLOCK = Uint(786432)

VERSIONED_HASH_VERSION_KZG

80
VERSIONED_HASH_VERSION_KZG = b"\x01"

BlockChain

History and current state of the block chain.

83
@dataclass
class BlockChain:

blocks

89
    blocks: List[Block]

state

90
    state: State

chain_id

91
    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:
95
    """
96
    Transforms the state from the previous hard fork (`old`) into the block
97
    chain object for this hard fork and returns it.
98
99
    When forks need to implement an irregular state transition, this function
100
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
101
    an example.
102
103
    Parameters
104
    ----------
105
    old :
106
        Previous block chain object.
107
108
    Returns
109
    -------
110
    new : `BlockChain`
111
        Upgraded block chain object for this hard fork.
112
    """
113
    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]:
117
    """
118
    Obtain the list of hashes of the previous 256 blocks in order of
119
    increasing block number.
120
121
    This function will return less hashes for the first 256 blocks.
122
123
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
124
    therefore this function retrieves them.
125
126
    Parameters
127
    ----------
128
    chain :
129
        History and current state.
130
131
    Returns
132
    -------
133
    recent_block_hashes : `List[Hash32]`
134
        Hashes of the recent 256 blocks in order of increasing block number.
135
    """
136
    recent_blocks = chain.blocks[-255:]
137
    # TODO: This function has not been tested rigorously
138
    if len(recent_blocks) == 0:
139
        return []
140
141
    recent_block_hashes = []
142
143
    for block in recent_blocks:
144
        prev_block_hash = block.header.parent_hash
145
        recent_block_hashes.append(prev_block_hash)
146
147
    # We are computing the hash only for the most recent block and not for
148
    # the rest of the blocks as they have successors which have the hash of
149
    # the current block as parent hash.
150
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
151
    recent_block_hashes.append(most_recent_block_hash)
152
153
    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:
157
    """
158
    Attempts to apply a block to an existing block chain.
159
160
    All parts of the block's contents need to be verified before being added
161
    to the chain. Blocks are verified by ensuring that the contents of the
162
    block make logical sense with the contents of the parent block. The
163
    information in the block's header must also match the corresponding
164
    information in the block.
165
166
    To implement Ethereum, in theory clients are only required to store the
167
    most recent 255 blocks of the chain since as far as execution is
168
    concerned, only those blocks are accessed. Practically, however, clients
169
    should store more blocks to handle reorgs.
170
171
    Parameters
172
    ----------
173
    chain :
174
        History and current state.
175
    block :
176
        Block to apply to `chain`.
177
    """
178
    parent_header = chain.blocks[-1].header
179
    excess_blob_gas = calculate_excess_blob_gas(parent_header)
180
    if block.header.excess_blob_gas != excess_blob_gas:
181
        raise InvalidBlock
182
183
    validate_header(block.header, parent_header)
184
    if block.ommers != ():
185
        raise InvalidBlock
186
    apply_body_output = apply_body(
187
        chain.state,
188
        get_last_256_block_hashes(chain),
189
        block.header.coinbase,
190
        block.header.number,
191
        block.header.base_fee_per_gas,
192
        block.header.gas_limit,
193
        block.header.timestamp,
194
        block.header.prev_randao,
195
        block.transactions,
196
        chain.chain_id,
197
        block.withdrawals,
198
        block.header.parent_beacon_block_root,
199
        excess_blob_gas,
200
    )
201
    if apply_body_output.block_gas_used != block.header.gas_used:
202
        raise InvalidBlock(
203
            f"{apply_body_output.block_gas_used} != {block.header.gas_used}"
204
        )
205
    if apply_body_output.transactions_root != block.header.transactions_root:
206
        raise InvalidBlock
207
    if apply_body_output.state_root != block.header.state_root:
208
        raise InvalidBlock
209
    if apply_body_output.receipt_root != block.header.receipt_root:
210
        raise InvalidBlock
211
    if apply_body_output.block_logs_bloom != block.header.bloom:
212
        raise InvalidBlock
213
    if apply_body_output.withdrawals_root != block.header.withdrawals_root:
214
        raise InvalidBlock
215
    if apply_body_output.blob_gas_used != block.header.blob_gas_used:
216
        raise InvalidBlock
217
218
    chain.blocks.append(block)
219
    if len(chain.blocks) > 255:
220
        # Real clients have to store more blocks to deal with reorgs, but the
221
        # protocol only requires the last 255
222
        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:
231
    """
232
    Calculates the base fee per gas for the block.
233
234
    Parameters
235
    ----------
236
    block_gas_limit :
237
        Gas limit of the block for which the base fee is being calculated.
238
    parent_gas_limit :
239
        Gas limit of the parent block.
240
    parent_gas_used :
241
        Gas used in the parent block.
242
    parent_base_fee_per_gas :
243
        Base fee per gas of the parent block.
244
245
    Returns
246
    -------
247
    base_fee_per_gas : `Uint`
248
        Base fee per gas for the block.
249
    """
250
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
251
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
252
        raise InvalidBlock
253
254
    if parent_gas_used == parent_gas_target:
255
        expected_base_fee_per_gas = parent_base_fee_per_gas
256
    elif parent_gas_used > parent_gas_target:
257
        gas_used_delta = parent_gas_used - parent_gas_target
258
259
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
260
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
261
262
        base_fee_per_gas_delta = max(
263
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
264
            Uint(1),
265
        )
266
267
        expected_base_fee_per_gas = (
268
            parent_base_fee_per_gas + base_fee_per_gas_delta
269
        )
270
    else:
271
        gas_used_delta = parent_gas_target - parent_gas_used
272
273
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
274
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
275
276
        base_fee_per_gas_delta = (
277
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
278
        )
279
280
        expected_base_fee_per_gas = (
281
            parent_base_fee_per_gas - base_fee_per_gas_delta
282
        )
283
284
    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:
288
    """
289
    Verifies a block header.
290
291
    In order to consider a block's header valid, the logic for the
292
    quantities in the header should match the logic for the block itself.
293
    For example the header timestamp should be greater than the block's parent
294
    timestamp because the block was created *after* the parent block.
295
    Additionally, the block's number should be directly following the parent
296
    block's number since it is the next block in the sequence.
297
298
    Parameters
299
    ----------
300
    header :
301
        Header to check for correctness.
302
    parent_header :
303
        Parent Header of the header to check for correctness
304
    """
305
    if header.gas_used > header.gas_limit:
306
        raise InvalidBlock
307
308
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
309
        header.gas_limit,
310
        parent_header.gas_limit,
311
        parent_header.gas_used,
312
        parent_header.base_fee_per_gas,
313
    )
314
    if expected_base_fee_per_gas != header.base_fee_per_gas:
315
        raise InvalidBlock
316
    if header.timestamp <= parent_header.timestamp:
317
        raise InvalidBlock
318
    if header.number != parent_header.number + Uint(1):
319
        raise InvalidBlock
320
    if len(header.extra_data) > 32:
321
        raise InvalidBlock
322
    if header.difficulty != 0:
323
        raise InvalidBlock
324
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
325
        raise InvalidBlock
326
    if header.ommers_hash != EMPTY_OMMER_HASH:
327
        raise InvalidBlock
328
329
    block_parent_hash = keccak256(rlp.encode(parent_header))
330
    if header.parent_hash != block_parent_hash:
331
        raise InvalidBlock

check_transaction

Check if the transaction is includable in the block.

Parameters

state : Current state. tx : The transaction. gas_available : The gas remaining in the block. chain_id : The ID of the current chain. base_fee_per_gas : The block base fee. excess_blob_gas : The excess blob gas.

Returns

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

Raises

InvalidBlock : If the transaction is not includable.

def check_transaction(state: State, ​​tx: Transaction, ​​gas_available: Uint, ​​chain_id: U64, ​​base_fee_per_gas: Uint, ​​excess_blob_gas: U64) -> Tuple[Address, Uint, Tuple[VersionedHash, ...]]:
342
    """
343
    Check if the transaction is includable in the block.
344
345
    Parameters
346
    ----------
347
    state :
348
        Current state.
349
    tx :
350
        The transaction.
351
    gas_available :
352
        The gas remaining in the block.
353
    chain_id :
354
        The ID of the current chain.
355
    base_fee_per_gas :
356
        The block base fee.
357
    excess_blob_gas :
358
        The excess blob gas.
359
360
    Returns
361
    -------
362
    sender_address :
363
        The sender of the transaction.
364
    effective_gas_price :
365
        The price to charge for gas when the transaction is executed.
366
    blob_versioned_hashes :
367
        The blob versioned hashes of the transaction.
368
369
    Raises
370
    ------
371
    InvalidBlock :
372
        If the transaction is not includable.
373
    """
374
    if tx.gas > gas_available:
375
        raise InvalidBlock
376
    sender_address = recover_sender(chain_id, tx)
377
    sender_account = get_account(state, sender_address)
378
379
    if isinstance(tx, (FeeMarketTransaction, BlobTransaction)):
380
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
381
            raise InvalidBlock
382
        if tx.max_fee_per_gas < base_fee_per_gas:
383
            raise InvalidBlock
384
385
        priority_fee_per_gas = min(
386
            tx.max_priority_fee_per_gas,
387
            tx.max_fee_per_gas - base_fee_per_gas,
388
        )
389
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
390
        max_gas_fee = tx.gas * tx.max_fee_per_gas
391
    else:
392
        if tx.gas_price < base_fee_per_gas:
393
            raise InvalidBlock
394
        effective_gas_price = tx.gas_price
395
        max_gas_fee = tx.gas * tx.gas_price
396
397
    if isinstance(tx, BlobTransaction):
398
        if not isinstance(tx.to, Address):
399
            raise InvalidBlock
400
        if len(tx.blob_versioned_hashes) == 0:
401
            raise InvalidBlock
402
        for blob_versioned_hash in tx.blob_versioned_hashes:
403
            if blob_versioned_hash[0:1] != VERSIONED_HASH_VERSION_KZG:
404
                raise InvalidBlock
405
406
        blob_gas_price = calculate_blob_gas_price(excess_blob_gas)
407
        if Uint(tx.max_fee_per_blob_gas) < blob_gas_price:
408
            raise InvalidBlock
409
410
        max_gas_fee += calculate_total_blob_gas(tx) * Uint(
411
            tx.max_fee_per_blob_gas
412
        )
413
        blob_versioned_hashes = tx.blob_versioned_hashes
414
    else:
415
        blob_versioned_hashes = ()
416
    if sender_account.nonce != tx.nonce:
417
        raise InvalidBlock
418
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
419
        raise InvalidBlock
420
    if sender_account.code != bytearray():
421
        raise InvalidSenderError("not EOA")
422
423
    return sender_address, effective_gas_price, blob_versioned_hashes

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[EthereumException], ​​cumulative_gas_used: Uint, ​​logs: Tuple[Log, ...]) -> Union[Bytes, Receipt]:
432
    """
433
    Make the receipt for a transaction that was executed.
434
435
    Parameters
436
    ----------
437
    tx :
438
        The executed transaction.
439
    error :
440
        Error in the top level frame of the transaction, if any.
441
    cumulative_gas_used :
442
        The total gas used so far in the block after the transaction was
443
        executed.
444
    logs :
445
        The logs produced by the transaction.
446
447
    Returns
448
    -------
449
    receipt :
450
        The receipt for the transaction.
451
    """
452
    receipt = Receipt(
453
        succeeded=error is None,
454
        cumulative_gas_used=cumulative_gas_used,
455
        bloom=logs_bloom(logs),
456
        logs=logs,
457
    )
458
459
    if isinstance(tx, AccessListTransaction):
460
        return b"\x01" + rlp.encode(receipt)
461
    elif isinstance(tx, FeeMarketTransaction):
462
        return b"\x02" + rlp.encode(receipt)
463
    elif isinstance(tx, BlobTransaction):
464
        return b"\x03" + rlp.encode(receipt)
465
    else:
466
        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. blob_gas_used : ethereum.base_types.Uint Total blob gas used in the block.

469
@dataclass
class ApplyBodyOutput:

block_gas_used

493
    block_gas_used: Uint

transactions_root

494
    transactions_root: Root

receipt_root

495
    receipt_root: Root

block_logs_bloom

496
    block_logs_bloom: Bloom

state_root

497
    state_root: Root

withdrawals_root

498
    withdrawals_root: Root

blob_gas_used

499
    blob_gas_used: Uint

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. parent_beacon_block_root : The root of the beacon block from the parent block. excess_blob_gas : Excess blob gas calculated from the previous 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, ...], ​​parent_beacon_block_root: Root, ​​excess_blob_gas: U64) -> ApplyBodyOutput:
517
    """
518
    Executes a block.
519
520
    Many of the contents of a block are stored in data structures called
521
    tries. There is a transactions trie which is similar to a ledger of the
522
    transactions stored in the current block. There is also a receipts trie
523
    which stores the results of executing a transaction, like the post state
524
    and gas used. This function creates and executes the block that is to be
525
    added to the chain.
526
527
    Parameters
528
    ----------
529
    state :
530
        Current account state.
531
    block_hashes :
532
        List of hashes of the previous 256 blocks in the order of
533
        increasing block number.
534
    coinbase :
535
        Address of account which receives block reward and transaction fees.
536
    block_number :
537
        Position of the block within the chain.
538
    base_fee_per_gas :
539
        Base fee per gas of within the block.
540
    block_gas_limit :
541
        Initial amount of gas available for execution in this block.
542
    block_time :
543
        Time the block was produced, measured in seconds since the epoch.
544
    prev_randao :
545
        The previous randao from the beacon chain.
546
    transactions :
547
        Transactions included in the block.
548
    ommers :
549
        Headers of ancestor blocks which are not direct parents (formerly
550
        uncles.)
551
    chain_id :
552
        ID of the executing chain.
553
    withdrawals :
554
        Withdrawals to be processed in the current block.
555
    parent_beacon_block_root :
556
        The root of the beacon block from the parent block.
557
    excess_blob_gas :
558
        Excess blob gas calculated from the previous block.
559
560
    Returns
561
    -------
562
    apply_body_output : `ApplyBodyOutput`
563
        Output of applying the block body to the state.
564
    """
565
    blob_gas_used = Uint(0)
566
    gas_available = block_gas_limit
567
    transactions_trie: Trie[
568
        Bytes, Optional[Union[Bytes, LegacyTransaction]]
569
    ] = Trie(secured=False, default=None)
570
    receipts_trie: Trie[Bytes, Optional[Union[Bytes, Receipt]]] = Trie(
571
        secured=False, default=None
572
    )
573
    withdrawals_trie: Trie[Bytes, Optional[Union[Bytes, Withdrawal]]] = Trie(
574
        secured=False, default=None
575
    )
576
    block_logs: Tuple[Log, ...] = ()
577
578
    beacon_block_roots_contract_code = get_account(
579
        state, BEACON_ROOTS_ADDRESS
580
    ).code
581
582
    system_tx_message = Message(
583
        caller=SYSTEM_ADDRESS,
584
        target=BEACON_ROOTS_ADDRESS,
585
        gas=SYSTEM_TRANSACTION_GAS,
586
        value=U256(0),
587
        data=parent_beacon_block_root,
588
        code=beacon_block_roots_contract_code,
589
        depth=Uint(0),
590
        current_target=BEACON_ROOTS_ADDRESS,
591
        code_address=BEACON_ROOTS_ADDRESS,
592
        should_transfer_value=False,
593
        is_static=False,
594
        accessed_addresses=set(),
595
        accessed_storage_keys=set(),
596
        parent_evm=None,
597
    )
598
599
    system_tx_env = vm.Environment(
600
        caller=SYSTEM_ADDRESS,
601
        origin=SYSTEM_ADDRESS,
602
        block_hashes=block_hashes,
603
        coinbase=coinbase,
604
        number=block_number,
605
        gas_limit=block_gas_limit,
606
        base_fee_per_gas=base_fee_per_gas,
607
        gas_price=base_fee_per_gas,
608
        time=block_time,
609
        prev_randao=prev_randao,
610
        state=state,
611
        chain_id=chain_id,
612
        traces=[],
613
        excess_blob_gas=excess_blob_gas,
614
        blob_versioned_hashes=(),
615
        transient_storage=TransientStorage(),
616
    )
617
618
    system_tx_output = process_message_call(system_tx_message, system_tx_env)
619
620
    destroy_touched_empty_accounts(
621
        system_tx_env.state, system_tx_output.touched_accounts
622
    )
623
624
    for i, tx in enumerate(map(decode_transaction, transactions)):
625
        trie_set(
626
            transactions_trie, rlp.encode(Uint(i)), encode_transaction(tx)
627
        )
628
629
        (
630
            sender_address,
631
            effective_gas_price,
632
            blob_versioned_hashes,
633
        ) = check_transaction(
634
            state,
635
            tx,
636
            gas_available,
637
            chain_id,
638
            base_fee_per_gas,
639
            excess_blob_gas,
640
        )
641
642
        env = vm.Environment(
643
            caller=sender_address,
644
            origin=sender_address,
645
            block_hashes=block_hashes,
646
            coinbase=coinbase,
647
            number=block_number,
648
            gas_limit=block_gas_limit,
649
            base_fee_per_gas=base_fee_per_gas,
650
            gas_price=effective_gas_price,
651
            time=block_time,
652
            prev_randao=prev_randao,
653
            state=state,
654
            chain_id=chain_id,
655
            traces=[],
656
            excess_blob_gas=excess_blob_gas,
657
            blob_versioned_hashes=blob_versioned_hashes,
658
            transient_storage=TransientStorage(),
659
        )
660
661
        gas_used, logs, error = process_transaction(env, tx)
662
        gas_available -= gas_used
663
664
        receipt = make_receipt(
665
            tx, error, (block_gas_limit - gas_available), logs
666
        )
667
668
        trie_set(
669
            receipts_trie,
670
            rlp.encode(Uint(i)),
671
            receipt,
672
        )
673
674
        block_logs += logs
675
        blob_gas_used += calculate_total_blob_gas(tx)
676
    if blob_gas_used > MAX_BLOB_GAS_PER_BLOCK:
677
        raise InvalidBlock
678
    block_gas_used = block_gas_limit - gas_available
679
680
    block_logs_bloom = logs_bloom(block_logs)
681
682
    for i, wd in enumerate(withdrawals):
683
        trie_set(withdrawals_trie, rlp.encode(Uint(i)), rlp.encode(wd))
684
685
        process_withdrawal(state, wd)
686
687
        if account_exists_and_is_empty(state, wd.address):
688
            destroy_account(state, wd.address)
689
690
    return ApplyBodyOutput(
691
        block_gas_used,
692
        root(transactions_trie),
693
        root(receipts_trie),
694
        block_logs_bloom,
695
        state_root(state),
696
        root(withdrawals_trie),
697
        blob_gas_used,
698
    )

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.cancun.vm.Environment, ​​tx: Transaction) -> Tuple[Uint, Tuple[Log, ...], Optional[EthereumException]]:
704
    """
705
    Execute a transaction against the provided environment.
706
707
    This function processes the actions needed to execute a transaction.
708
    It decrements the sender's account after calculating the gas fee and
709
    refunds them the proper amount after execution. Calling contracts,
710
    deploying code, and incrementing nonces are all examples of actions that
711
    happen within this function or from a call made within this function.
712
713
    Accounts that are marked for deletion are processed and destroyed after
714
    execution.
715
716
    Parameters
717
    ----------
718
    env :
719
        Environment for the Ethereum Virtual Machine.
720
    tx :
721
        Transaction to execute.
722
723
    Returns
724
    -------
725
    gas_left : `ethereum.base_types.U256`
726
        Remaining gas after execution.
727
    logs : `Tuple[ethereum.blocks.Log, ...]`
728
        Logs generated during execution.
729
    """
730
    if not validate_transaction(tx):
731
        raise InvalidBlock
732
733
    sender = env.origin
734
    sender_account = get_account(env.state, sender)
735
736
    if isinstance(tx, BlobTransaction):
737
        blob_gas_fee = calculate_data_fee(env.excess_blob_gas, tx)
738
    else:
739
        blob_gas_fee = Uint(0)
740
741
    effective_gas_fee = tx.gas * env.gas_price
742
743
    gas = tx.gas - calculate_intrinsic_cost(tx)
744
    increment_nonce(env.state, sender)
745
746
    sender_balance_after_gas_fee = (
747
        Uint(sender_account.balance) - effective_gas_fee - blob_gas_fee
748
    )
749
    set_account_balance(env.state, sender, U256(sender_balance_after_gas_fee))
750
751
    preaccessed_addresses = set()
752
    preaccessed_storage_keys = set()
753
    preaccessed_addresses.add(env.coinbase)
754
    if isinstance(
755
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
756
    ):
757
        for address, keys in tx.access_list:
758
            preaccessed_addresses.add(address)
759
            for key in keys:
760
                preaccessed_storage_keys.add((address, key))
761
762
    message = prepare_message(
763
        sender,
764
        tx.to,
765
        tx.value,
766
        tx.data,
767
        gas,
768
        env,
769
        preaccessed_addresses=frozenset(preaccessed_addresses),
770
        preaccessed_storage_keys=frozenset(preaccessed_storage_keys),
771
    )
772
773
    output = process_message_call(message, env)
774
775
    gas_used = tx.gas - output.gas_left
776
    gas_refund = min(gas_used // Uint(5), Uint(output.refund_counter))
777
    gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price
778
779
    # For non-1559 transactions env.gas_price == tx.gas_price
780
    priority_fee_per_gas = env.gas_price - env.base_fee_per_gas
781
    transaction_fee = (
782
        tx.gas - output.gas_left - gas_refund
783
    ) * priority_fee_per_gas
784
785
    total_gas_used = gas_used - gas_refund
786
787
    # refund gas
788
    sender_balance_after_refund = get_account(
789
        env.state, sender
790
    ).balance + U256(gas_refund_amount)
791
    set_account_balance(env.state, sender, sender_balance_after_refund)
792
793
    # transfer miner fees
794
    coinbase_balance_after_mining_fee = get_account(
795
        env.state, env.coinbase
796
    ).balance + U256(transaction_fee)
797
    if coinbase_balance_after_mining_fee != 0:
798
        set_account_balance(
799
            env.state, env.coinbase, coinbase_balance_after_mining_fee
800
        )
801
    elif account_exists_and_is_empty(env.state, env.coinbase):
802
        destroy_account(env.state, env.coinbase)
803
804
    for address in output.accounts_to_delete:
805
        destroy_account(env.state, address)
806
807
    destroy_touched_empty_accounts(env.state, output.touched_accounts)
808
809
    return total_gas_used, output.logs, output.error

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:
813
    """
814
    Computes the hash of a block header.
815
816
    The header hash of a block is the canonical hash that is used to refer
817
    to a specific block and completely distinguishes a block from another.
818
819
    ``keccak256`` is a function that produces a 256 bit hash of any input.
820
    It also takes in any number of bytes as an input and produces a single
821
    hash for them. A hash is a completely unique output for a single input.
822
    So an input corresponds to one unique hash that can be used to identify
823
    the input exactly.
824
825
    Prior to using the ``keccak256`` hash function, the header must be
826
    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
827
    RLP encoding the header converts it into a space-efficient format that
828
    allows for easy transfer of data between nodes. The purpose of RLP is to
829
    encode arbitrarily nested arrays of binary data, and RLP is the primary
830
    encoding method used to serialize objects in Ethereum's execution layer.
831
    The only purpose of RLP is to encode structure; encoding specific data
832
    types (e.g. strings, floats) is left up to higher-order protocols.
833
834
    Parameters
835
    ----------
836
    header :
837
        Header of interest.
838
839
    Returns
840
    -------
841
    hash : `ethereum.crypto.hash.Hash32`
842
        Hash of the header.
843
    """
844
    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:
848
    """
849
    Validates the gas limit for a block.
850
851
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
852
    quotient of the parent block's gas limit and the
853
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
854
    passed through as a parameter is greater than or equal to the *sum* of
855
    the parent's gas and the adjustment delta then the limit for gas is too
856
    high and fails this function's check. Similarly, if the limit is less
857
    than or equal to the *difference* of the parent's gas and the adjustment
858
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
859
    check fails because the gas limit doesn't allow for a sufficient or
860
    reasonable amount of gas to be used on a block.
861
862
    Parameters
863
    ----------
864
    gas_limit :
865
        Gas limit to validate.
866
867
    parent_gas_limit :
868
        Gas limit of the parent block.
869
870
    Returns
871
    -------
872
    check : `bool`
873
        True if gas limit constraints are satisfied, False otherwise.
874
    """
875
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
876
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
877
        return False
878
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
879
        return False
880
    if gas_limit < GAS_LIMIT_MINIMUM:
881
        return False
882
883
    return True