ethereum.shanghai.forkethereum.cancun.fork

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

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

Introduction

Entry point for the Ethereum specification.

BASE_FEE_MAX_CHANGE_DENOMINATOR

65
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

66
ELASTICITY_MULTIPLIER = Uint(2)

GAS_LIMIT_ADJUSTMENT_FACTOR

67
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

68
GAS_LIMIT_MINIMUM = Uint(5000)

EMPTY_OMMER_HASH

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

SYSTEM_ADDRESS

70
SYSTEM_ADDRESS = hex_to_address("0xfffffffffffffffffffffffffffffffffffffffe")

BEACON_ROOTS_ADDRESS

71
BEACON_ROOTS_ADDRESS = hex_to_address(
72
    "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"
73
)

SYSTEM_TRANSACTION_GAS

74
SYSTEM_TRANSACTION_GAS = Uint(30000000)

MAX_BLOB_GAS_PER_BLOCK

75
MAX_BLOB_GAS_PER_BLOCK = Uint(786432)

VERSIONED_HASH_VERSION_KZG

76
VERSIONED_HASH_VERSION_KZG = b"\x01"

BlockChain

History and current state of the block chain.

79
@dataclass
class BlockChain:

blocks

85
    blocks: List[Block]

state

86
    state: State

chain_id

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

check_transaction

Check if the transaction is includable in the block.

Parameters

state : Current state. 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. 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, ​​base_fee_per_gas: Uint, ​​gas_available: Uint, ​​chain_id: U64, ​​base_fee_per_gas: Uintexcess_blob_gas: U64) -> Tuple[Address, Uint, Tuple[VersionedHash, ...]]:
338
    """
339
    Check if the transaction is includable in the block.
340
341
    Parameters
342
    ----------
343
    state :
344
        Current state.
345
    tx :
346
        The transaction.
317
    base_fee_per_gas :
318
        The block base fee.
347
    gas_available :
348
        The gas remaining in the block.
349
    chain_id :
350
        The ID of the current chain.
351
    base_fee_per_gas :
352
        The block base fee.
353
    excess_blob_gas :
354
        The excess blob gas.
355
356
    Returns
357
    -------
358
    sender_address :
359
        The sender of the transaction.
360
    effective_gas_price :
361
        The price to charge for gas when the transaction is executed.
362
    blob_versioned_hashes :
363
        The blob versioned hashes of the transaction.
364
365
    Raises
366
    ------
367
    InvalidBlock :
368
        If the transaction is not includable.
369
    """
370
    if tx.gas > gas_available:
371
        raise InvalidBlock
372
    sender_address = recover_sender(chain_id, tx)
373
    sender_account = get_account(state, sender_address)
374
340
    if isinstance(tx, FeeMarketTransaction):
375
    if isinstance(tx, (FeeMarketTransaction, BlobTransaction)):
376
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
377
            raise InvalidBlock
378
        if tx.max_fee_per_gas < base_fee_per_gas:
379
            raise InvalidBlock
380
381
        priority_fee_per_gas = min(
382
            tx.max_priority_fee_per_gas,
383
            tx.max_fee_per_gas - base_fee_per_gas,
384
        )
350
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
385
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
386
        max_gas_fee = tx.gas * tx.max_fee_per_gas
387
    else:
388
        if tx.gas_price < base_fee_per_gas:
389
            raise InvalidBlock
354
        effective_gas_price = tx.gas_price
390
        effective_gas_price = tx.gas_price
391
        max_gas_fee = tx.gas * tx.gas_price
392
356
    return sender_address, effective_gas_price
393
    if isinstance(tx, BlobTransaction):
394
        if not isinstance(tx.to, Address):
395
            raise InvalidBlock
396
        if len(tx.blob_versioned_hashes) == 0:
397
            raise InvalidBlock
398
        for blob_versioned_hash in tx.blob_versioned_hashes:
399
            if blob_versioned_hash[0:1] != VERSIONED_HASH_VERSION_KZG:
400
                raise InvalidBlock
401
402
        blob_gas_price = calculate_blob_gas_price(excess_blob_gas)
403
        if Uint(tx.max_fee_per_blob_gas) < blob_gas_price:
404
            raise InvalidBlock
405
406
        max_gas_fee += calculate_total_blob_gas(tx) * Uint(
407
            tx.max_fee_per_blob_gas
408
        )
409
        blob_versioned_hashes = tx.blob_versioned_hashes
410
    else:
411
        blob_versioned_hashes = ()
412
    if sender_account.nonce != tx.nonce:
413
        raise InvalidBlock
414
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
415
        raise InvalidBlock
416
    if sender_account.code != bytearray():
417
        raise InvalidSenderError("not EOA")
418
419
    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[Exception], ​​cumulative_gas_used: Uint, ​​logs: Tuple[Log, ...]) -> Union[Bytes, Receipt]:
428
    """
429
    Make the receipt for a transaction that was executed.
430
431
    Parameters
432
    ----------
433
    tx :
434
        The executed transaction.
435
    error :
436
        Error in the top level frame of the transaction, if any.
437
    cumulative_gas_used :
438
        The total gas used so far in the block after the transaction was
439
        executed.
440
    logs :
441
        The logs produced by the transaction.
442
443
    Returns
444
    -------
445
    receipt :
446
        The receipt for the transaction.
447
    """
448
    receipt = Receipt(
449
        succeeded=error is None,
450
        cumulative_gas_used=cumulative_gas_used,
451
        bloom=logs_bloom(logs),
452
        logs=logs,
453
    )
454
455
    if isinstance(tx, AccessListTransaction):
456
        return b"\x01" + rlp.encode(receipt)
457
    elif isinstance(tx, FeeMarketTransaction):
458
        return b"\x02" + rlp.encode(receipt)
396
    else:
397
        return receipt
459
    elif isinstance(tx, BlobTransaction):
460
        return b"\x03" + rlp.encode(receipt)
461
    else:
462
        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.

465
@dataclass
class ApplyBodyOutput:

block_gas_used

489
    block_gas_used: Uint

transactions_root

490
    transactions_root: Root

receipt_root

491
    receipt_root: Root

block_logs_bloom

492
    block_logs_bloom: Bloom

state_root

493
    state_root: Root

withdrawals_root

494
    withdrawals_root: Root

blob_gas_used

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

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.Environmentethereum.cancun.vm.Environment, ​​tx: Transaction) -> Tuple[Uint, Tuple[Log, ...], Optional[Exception]]:
700
    """
701
    Execute a transaction against the provided environment.
702
703
    This function processes the actions needed to execute a transaction.
704
    It decrements the sender's account after calculating the gas fee and
705
    refunds them the proper amount after execution. Calling contracts,
706
    deploying code, and incrementing nonces are all examples of actions that
707
    happen within this function or from a call made within this function.
708
709
    Accounts that are marked for deletion are processed and destroyed after
710
    execution.
711
712
    Parameters
713
    ----------
714
    env :
715
        Environment for the Ethereum Virtual Machine.
716
    tx :
717
        Transaction to execute.
718
719
    Returns
720
    -------
721
    gas_left : `ethereum.base_types.U256`
722
        Remaining gas after execution.
723
    logs : `Tuple[ethereum.blocks.Log, ...]`
724
        Logs generated during execution.
725
    """
726
    if not validate_transaction(tx):
727
        raise InvalidBlock
728
729
    sender = env.origin
730
    sender_account = get_account(env.state, sender)
731
596
    if isinstance(tx, FeeMarketTransaction):
597
        max_gas_fee = tx.gas * tx.max_fee_per_gas
732
    if isinstance(tx, BlobTransaction):
733
        blob_gas_fee = calculate_data_fee(env.excess_blob_gas, tx)
734
    else:
599
        max_gas_fee = tx.gas * tx.gas_price
600
    if sender_account.nonce != tx.nonce:
601
        raise InvalidBlock
602
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
603
        raise InvalidBlock
604
    if sender_account.code != bytearray():
605
        raise InvalidSenderError("not EOA")
735
        blob_gas_fee = Uint(0)
736
737
    effective_gas_fee = tx.gas * env.gas_price
738
739
    gas = tx.gas - calculate_intrinsic_cost(tx)
740
    increment_nonce(env.state, sender)
741
742
    sender_balance_after_gas_fee = (
613
        Uint(sender_account.balance) - effective_gas_fee
743
        Uint(sender_account.balance) - effective_gas_fee - blob_gas_fee
744
    )
745
    set_account_balance(env.state, sender, U256(sender_balance_after_gas_fee))
746
747
    preaccessed_addresses = set()
748
    preaccessed_storage_keys = set()
749
    preaccessed_addresses.add(env.coinbase)
620
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
750
    if isinstance(
751
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
752
    ):
753
        for address, keys in tx.access_list:
754
            preaccessed_addresses.add(address)
755
            for key in keys:
756
                preaccessed_storage_keys.add((address, key))
757
758
    message = prepare_message(
759
        sender,
760
        tx.to,
761
        tx.value,
762
        tx.data,
763
        gas,
764
        env,
765
        preaccessed_addresses=frozenset(preaccessed_addresses),
766
        preaccessed_storage_keys=frozenset(preaccessed_storage_keys),
767
    )
768
769
    output = process_message_call(message, env)
770
771
    gas_used = tx.gas - output.gas_left
772
    gas_refund = min(gas_used // Uint(5), Uint(output.refund_counter))
773
    gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price
774
775
    # For non-1559 transactions env.gas_price == tx.gas_price
776
    priority_fee_per_gas = env.gas_price - env.base_fee_per_gas
777
    transaction_fee = (
778
        tx.gas - output.gas_left - gas_refund
779
    ) * priority_fee_per_gas
780
781
    total_gas_used = gas_used - gas_refund
782
783
    # refund gas
784
    sender_balance_after_refund = get_account(
785
        env.state, sender
786
    ).balance + U256(gas_refund_amount)
787
    set_account_balance(env.state, sender, sender_balance_after_refund)
788
789
    # transfer miner fees
790
    coinbase_balance_after_mining_fee = get_account(
791
        env.state, env.coinbase
792
    ).balance + U256(transaction_fee)
793
    if coinbase_balance_after_mining_fee != 0:
794
        set_account_balance(
795
            env.state, env.coinbase, coinbase_balance_after_mining_fee
796
        )
797
    elif account_exists_and_is_empty(env.state, env.coinbase):
798
        destroy_account(env.state, env.coinbase)
799
800
    for address in output.accounts_to_delete:
801
        destroy_account(env.state, address)
802
671
    for address in output.touched_accounts:
672
        if account_exists_and_is_empty(env.state, address):
673
            destroy_account(env.state, address)
803
    destroy_touched_empty_accounts(env.state, output.touched_accounts)
804
805
    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:
809
    """
810
    Computes the hash of a block header.
811
812
    The header hash of a block is the canonical hash that is used to refer
813
    to a specific block and completely distinguishes a block from another.
814
815
    ``keccak256`` is a function that produces a 256 bit hash of any input.
816
    It also takes in any number of bytes as an input and produces a single
817
    hash for them. A hash is a completely unique output for a single input.
818
    So an input corresponds to one unique hash that can be used to identify
819
    the input exactly.
820
821
    Prior to using the ``keccak256`` hash function, the header must be
822
    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
823
    RLP encoding the header converts it into a space-efficient format that
824
    allows for easy transfer of data between nodes. The purpose of RLP is to
825
    encode arbitrarily nested arrays of binary data, and RLP is the primary
826
    encoding method used to serialize objects in Ethereum's execution layer.
827
    The only purpose of RLP is to encode structure; encoding specific data
828
    types (e.g. strings, floats) is left up to higher-order protocols.
829
830
    Parameters
831
    ----------
832
    header :
833
        Header of interest.
834
835
    Returns
836
    -------
837
    hash : `ethereum.crypto.hash.Hash32`
838
        Hash of the header.
839
    """
840
    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:
844
    """
845
    Validates the gas limit for a block.
846
847
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
848
    quotient of the parent block's gas limit and the
849
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
850
    passed through as a parameter is greater than or equal to the *sum* of
851
    the parent's gas and the adjustment delta then the limit for gas is too
852
    high and fails this function's check. Similarly, if the limit is less
853
    than or equal to the *difference* of the parent's gas and the adjustment
854
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
855
    check fails because the gas limit doesn't allow for a sufficient or
856
    reasonable amount of gas to be used on a block.
857
858
    Parameters
859
    ----------
860
    gas_limit :
861
        Gas limit to validate.
862
863
    parent_gas_limit :
864
        Gas limit of the parent block.
865
866
    Returns
867
    -------
868
    check : `bool`
869
        True if gas limit constraints are satisfied, False otherwise.
870
    """
871
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
872
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
873
        return False
874
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
875
        return False
876
    if gas_limit < GAS_LIMIT_MINIMUM:
877
        return False
878
879
    return True