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

70
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

71
ELASTICITY_MULTIPLIER = Uint(2)

GAS_LIMIT_ADJUSTMENT_FACTOR

72
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

73
GAS_LIMIT_MINIMUM = Uint(5000)

EMPTY_OMMER_HASH

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

SYSTEM_ADDRESS

75
SYSTEM_ADDRESS = hex_to_address("0xfffffffffffffffffffffffffffffffffffffffe")

BEACON_ROOTS_ADDRESS

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

SYSTEM_TRANSACTION_GAS

79
SYSTEM_TRANSACTION_GAS = Uint(30000000)

MAX_BLOB_GAS_PER_BLOCK

80
MAX_BLOB_GAS_PER_BLOCK = Uint(786432)

VERSIONED_HASH_VERSION_KZG

81
VERSIONED_HASH_VERSION_KZG = b"\x01"

BlockChain

History and current state of the block chain.

84
@dataclass
class BlockChain:

blocks

90
    blocks: List[Block]

state

91
    state: State

chain_id

92
    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:
96
    """
97
    Transforms the state from the previous hard fork (`old`) into the block
98
    chain object for this hard fork and returns it.
99
100
    When forks need to implement an irregular state transition, this function
101
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
102
    an example.
103
104
    Parameters
105
    ----------
106
    old :
107
        Previous block chain object.
108
109
    Returns
110
    -------
111
    new : `BlockChain`
112
        Upgraded block chain object for this hard fork.
113
    """
114
    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]:
118
    """
119
    Obtain the list of hashes of the previous 256 blocks in order of
120
    increasing block number.
121
122
    This function will return less hashes for the first 256 blocks.
123
124
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
125
    therefore this function retrieves them.
126
127
    Parameters
128
    ----------
129
    chain :
130
        History and current state.
131
132
    Returns
133
    -------
134
    recent_block_hashes : `List[Hash32]`
135
        Hashes of the recent 256 blocks in order of increasing block number.
136
    """
137
    recent_blocks = chain.blocks[-255:]
138
    # TODO: This function has not been tested rigorously
139
    if len(recent_blocks) == 0:
140
        return []
141
142
    recent_block_hashes = []
143
144
    for block in recent_blocks:
145
        prev_block_hash = block.header.parent_hash
146
        recent_block_hashes.append(prev_block_hash)
147
148
    # We are computing the hash only for the most recent block and not for
149
    # the rest of the blocks as they have successors which have the hash of
150
    # the current block as parent hash.
151
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
152
    recent_block_hashes.append(most_recent_block_hash)
153
154
    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:
158
    """
159
    Attempts to apply a block to an existing block chain.
160
161
    All parts of the block's contents need to be verified before being added
162
    to the chain. Blocks are verified by ensuring that the contents of the
163
    block make logical sense with the contents of the parent block. The
164
    information in the block's header must also match the corresponding
165
    information in the block.
166
167
    To implement Ethereum, in theory clients are only required to store the
168
    most recent 255 blocks of the chain since as far as execution is
169
    concerned, only those blocks are accessed. Practically, however, clients
170
    should store more blocks to handle reorgs.
171
172
    Parameters
173
    ----------
174
    chain :
175
        History and current state.
176
    block :
177
        Block to apply to `chain`.
178
    """
179
    parent_header = chain.blocks[-1].header
180
    excess_blob_gas = calculate_excess_blob_gas(parent_header)
181
    if block.header.excess_blob_gas != excess_blob_gas:
182
        raise InvalidBlock
183
184
    validate_header(block.header, parent_header)
185
    if block.ommers != ():
186
        raise InvalidBlock
187
    apply_body_output = apply_body(
188
        chain.state,
189
        get_last_256_block_hashes(chain),
190
        block.header.coinbase,
191
        block.header.number,
192
        block.header.base_fee_per_gas,
193
        block.header.gas_limit,
194
        block.header.timestamp,
195
        block.header.prev_randao,
196
        block.transactions,
197
        chain.chain_id,
198
        block.withdrawals,
199
        block.header.parent_beacon_block_root,
200
        excess_blob_gas,
201
    )
202
    if apply_body_output.block_gas_used != block.header.gas_used:
203
        raise InvalidBlock(
204
            f"{apply_body_output.block_gas_used} != {block.header.gas_used}"
205
        )
206
    if apply_body_output.transactions_root != block.header.transactions_root:
207
        raise InvalidBlock
208
    if apply_body_output.state_root != block.header.state_root:
209
        raise InvalidBlock
210
    if apply_body_output.receipt_root != block.header.receipt_root:
211
        raise InvalidBlock
212
    if apply_body_output.block_logs_bloom != block.header.bloom:
213
        raise InvalidBlock
214
    if apply_body_output.withdrawals_root != block.header.withdrawals_root:
215
        raise InvalidBlock
216
    if apply_body_output.blob_gas_used != block.header.blob_gas_used:
217
        raise InvalidBlock
218
219
    chain.blocks.append(block)
220
    if len(chain.blocks) > 255:
221
        # Real clients have to store more blocks to deal with reorgs, but the
222
        # protocol only requires the last 255
223
        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:
232
    """
233
    Calculates the base fee per gas for the block.
234
235
    Parameters
236
    ----------
237
    block_gas_limit :
238
        Gas limit of the block for which the base fee is being calculated.
239
    parent_gas_limit :
240
        Gas limit of the parent block.
241
    parent_gas_used :
242
        Gas used in the parent block.
243
    parent_base_fee_per_gas :
244
        Base fee per gas of the parent block.
245
246
    Returns
247
    -------
248
    base_fee_per_gas : `Uint`
249
        Base fee per gas for the block.
250
    """
251
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
252
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
253
        raise InvalidBlock
254
255
    if parent_gas_used == parent_gas_target:
256
        expected_base_fee_per_gas = parent_base_fee_per_gas
257
    elif parent_gas_used > parent_gas_target:
258
        gas_used_delta = parent_gas_used - parent_gas_target
259
260
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
261
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
262
263
        base_fee_per_gas_delta = max(
264
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
265
            Uint(1),
266
        )
267
268
        expected_base_fee_per_gas = (
269
            parent_base_fee_per_gas + base_fee_per_gas_delta
270
        )
271
    else:
272
        gas_used_delta = parent_gas_target - parent_gas_used
273
274
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
275
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
276
277
        base_fee_per_gas_delta = (
278
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
279
        )
280
281
        expected_base_fee_per_gas = (
282
            parent_base_fee_per_gas - base_fee_per_gas_delta
283
        )
284
285
    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:
289
    """
290
    Verifies a block header.
291
292
    In order to consider a block's header valid, the logic for the
293
    quantities in the header should match the logic for the block itself.
294
    For example the header timestamp should be greater than the block's parent
295
    timestamp because the block was created *after* the parent block.
296
    Additionally, the block's number should be directly following the parent
297
    block's number since it is the next block in the sequence.
298
299
    Parameters
300
    ----------
301
    header :
302
        Header to check for correctness.
303
    parent_header :
304
        Parent Header of the header to check for correctness
305
    """
306
    if header.gas_used > header.gas_limit:
307
        raise InvalidBlock
308
309
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
310
        header.gas_limit,
311
        parent_header.gas_limit,
312
        parent_header.gas_used,
313
        parent_header.base_fee_per_gas,
314
    )
315
    if expected_base_fee_per_gas != header.base_fee_per_gas:
316
        raise InvalidBlock
317
    if header.timestamp <= parent_header.timestamp:
318
        raise InvalidBlock
319
    if header.number != parent_header.number + Uint(1):
320
        raise InvalidBlock
321
    if len(header.extra_data) > 32:
322
        raise InvalidBlock
323
    if header.difficulty != 0:
324
        raise InvalidBlock
325
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
326
        raise InvalidBlock
327
    if header.ommers_hash != EMPTY_OMMER_HASH:
328
        raise InvalidBlock
329
330
    block_parent_hash = keccak256(rlp.encode(parent_header))
331
    if header.parent_hash != block_parent_hash:
332
        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, ...]]:
343
    """
344
    Check if the transaction is includable in the block.
345
346
    Parameters
347
    ----------
348
    state :
349
        Current state.
350
    tx :
351
        The transaction.
322
    base_fee_per_gas :
323
        The block base fee.
352
    gas_available :
353
        The gas remaining in the block.
354
    chain_id :
355
        The ID of the current chain.
356
    base_fee_per_gas :
357
        The block base fee.
358
    excess_blob_gas :
359
        The excess blob gas.
360
361
    Returns
362
    -------
363
    sender_address :
364
        The sender of the transaction.
365
    effective_gas_price :
366
        The price to charge for gas when the transaction is executed.
367
    blob_versioned_hashes :
368
        The blob versioned hashes of the transaction.
369
370
    Raises
371
    ------
372
    InvalidBlock :
373
        If the transaction is not includable.
374
    """
375
    if calculate_intrinsic_cost(tx) > tx.gas:
376
        raise InvalidBlock
377
    if tx.nonce >= U256(U64.MAX_VALUE):
378
        raise InvalidBlock
379
    if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE:
380
        raise InvalidBlock
381
382
    if tx.gas > gas_available:
383
        raise InvalidBlock
343
    sender_address = recover_sender(chain_id, tx)
384
345
    if isinstance(tx, FeeMarketTransaction):
385
    sender = recover_sender(chain_id, tx)
386
    sender_account = get_account(state, sender)
387
388
    if isinstance(tx, (FeeMarketTransaction, BlobTransaction)):
389
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
390
            raise InvalidBlock
391
        if tx.max_fee_per_gas < base_fee_per_gas:
392
            raise InvalidBlock
393
394
        priority_fee_per_gas = min(
395
            tx.max_priority_fee_per_gas,
396
            tx.max_fee_per_gas - base_fee_per_gas,
397
        )
355
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
398
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
399
        max_gas_fee = tx.gas * tx.max_fee_per_gas
400
    else:
401
        if tx.gas_price < base_fee_per_gas:
402
            raise InvalidBlock
359
        effective_gas_price = tx.gas_price
403
        effective_gas_price = tx.gas_price
404
        max_gas_fee = tx.gas * tx.gas_price
405
361
    return sender_address, effective_gas_price
406
    if isinstance(tx, BlobTransaction):
407
        if not isinstance(tx.to, Address):
408
            raise InvalidBlock
409
        if len(tx.blob_versioned_hashes) == 0:
410
            raise InvalidBlock
411
        for blob_versioned_hash in tx.blob_versioned_hashes:
412
            if blob_versioned_hash[0:1] != VERSIONED_HASH_VERSION_KZG:
413
                raise InvalidBlock
414
415
        blob_gas_price = calculate_blob_gas_price(excess_blob_gas)
416
        if Uint(tx.max_fee_per_blob_gas) < blob_gas_price:
417
            raise InvalidBlock
418
419
        max_gas_fee += calculate_total_blob_gas(tx) * Uint(
420
            tx.max_fee_per_blob_gas
421
        )
422
        blob_versioned_hashes = tx.blob_versioned_hashes
423
    else:
424
        blob_versioned_hashes = ()
425
    if sender_account.nonce != tx.nonce:
426
        raise InvalidBlock
427
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
428
        raise InvalidBlock
429
    if sender_account.code != bytearray():
430
        raise InvalidSenderError("not EOA")
431
432
    return sender, 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]:
441
    """
442
    Make the receipt for a transaction that was executed.
443
444
    Parameters
445
    ----------
446
    tx :
447
        The executed transaction.
448
    error :
449
        Error in the top level frame of the transaction, if any.
450
    cumulative_gas_used :
451
        The total gas used so far in the block after the transaction was
452
        executed.
453
    logs :
454
        The logs produced by the transaction.
455
456
    Returns
457
    -------
458
    receipt :
459
        The receipt for the transaction.
460
    """
461
    receipt = Receipt(
462
        succeeded=error is None,
463
        cumulative_gas_used=cumulative_gas_used,
464
        bloom=logs_bloom(logs),
465
        logs=logs,
466
    )
467
468
    if isinstance(tx, AccessListTransaction):
469
        return b"\x01" + rlp.encode(receipt)
470
    elif isinstance(tx, FeeMarketTransaction):
471
        return b"\x02" + rlp.encode(receipt)
401
    else:
402
        return receipt
472
    elif isinstance(tx, BlobTransaction):
473
        return b"\x03" + rlp.encode(receipt)
474
    else:
475
        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.

478
@dataclass
class ApplyBodyOutput:

block_gas_used

502
    block_gas_used: Uint

transactions_root

503
    transactions_root: Root

receipt_root

504
    receipt_root: Root

block_logs_bloom

505
    block_logs_bloom: Bloom

state_root

506
    state_root: Root

withdrawals_root

507
    withdrawals_root: Root

blob_gas_used

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

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]]:
713
    """
714
    Execute a transaction against the provided environment.
715
716
    This function processes the actions needed to execute a transaction.
717
    It decrements the sender's account after calculating the gas fee and
718
    refunds them the proper amount after execution. Calling contracts,
719
    deploying code, and incrementing nonces are all examples of actions that
720
    happen within this function or from a call made within this function.
721
722
    Accounts that are marked for deletion are processed and destroyed after
723
    execution.
724
725
    Parameters
726
    ----------
727
    env :
728
        Environment for the Ethereum Virtual Machine.
729
    tx :
730
        Transaction to execute.
731
732
    Returns
733
    -------
734
    gas_left : `ethereum.base_types.U256`
735
        Remaining gas after execution.
736
    logs : `Tuple[ethereum.blocks.Log, ...]`
737
        Logs generated during execution.
738
    """
595
    if not validate_transaction(tx):
596
        raise InvalidBlock
597
739
    sender = env.origin
740
    sender_account = get_account(env.state, sender)
741
601
    if isinstance(tx, FeeMarketTransaction):
602
        max_gas_fee = tx.gas * tx.max_fee_per_gas
742
    if isinstance(tx, BlobTransaction):
743
        blob_gas_fee = calculate_data_fee(env.excess_blob_gas, tx)
744
    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")
745
        blob_gas_fee = Uint(0)
746
747
    effective_gas_fee = tx.gas * env.gas_price
748
749
    gas = tx.gas - calculate_intrinsic_cost(tx)
750
    increment_nonce(env.state, sender)
751
752
    sender_balance_after_gas_fee = (
618
        Uint(sender_account.balance) - effective_gas_fee
753
        Uint(sender_account.balance) - effective_gas_fee - blob_gas_fee
754
    )
755
    set_account_balance(env.state, sender, U256(sender_balance_after_gas_fee))
756
757
    preaccessed_addresses = set()
758
    preaccessed_storage_keys = set()
759
    preaccessed_addresses.add(env.coinbase)
625
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
760
    if isinstance(
761
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
762
    ):
763
        for address, keys in tx.access_list:
764
            preaccessed_addresses.add(address)
765
            for key in keys:
766
                preaccessed_storage_keys.add((address, key))
767
768
    message = prepare_message(
769
        sender,
770
        tx.to,
771
        tx.value,
772
        tx.data,
773
        gas,
774
        env,
775
        preaccessed_addresses=frozenset(preaccessed_addresses),
776
        preaccessed_storage_keys=frozenset(preaccessed_storage_keys),
777
    )
778
779
    output = process_message_call(message, env)
780
781
    gas_used = tx.gas - output.gas_left
782
    gas_refund = min(gas_used // Uint(5), Uint(output.refund_counter))
783
    gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price
784
785
    # For non-1559 transactions env.gas_price == tx.gas_price
786
    priority_fee_per_gas = env.gas_price - env.base_fee_per_gas
787
    transaction_fee = (
788
        tx.gas - output.gas_left - gas_refund
789
    ) * priority_fee_per_gas
790
791
    total_gas_used = gas_used - gas_refund
792
793
    # refund gas
794
    sender_balance_after_refund = get_account(
795
        env.state, sender
796
    ).balance + U256(gas_refund_amount)
797
    set_account_balance(env.state, sender, sender_balance_after_refund)
798
799
    # transfer miner fees
800
    coinbase_balance_after_mining_fee = get_account(
801
        env.state, env.coinbase
802
    ).balance + U256(transaction_fee)
803
    if coinbase_balance_after_mining_fee != 0:
804
        set_account_balance(
805
            env.state, env.coinbase, coinbase_balance_after_mining_fee
806
        )
807
    elif account_exists_and_is_empty(env.state, env.coinbase):
808
        destroy_account(env.state, env.coinbase)
809
810
    for address in output.accounts_to_delete:
811
        destroy_account(env.state, address)
812
676
    for address in output.touched_accounts:
677
        if account_exists_and_is_empty(env.state, address):
678
            destroy_account(env.state, address)
813
    destroy_touched_empty_accounts(env.state, output.touched_accounts)
814
815
    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:
819
    """
820
    Calculates the gas that is charged before execution is started.
821
822
    The intrinsic cost of the transaction is charged before execution has
823
    begun. Functions/operations in the EVM cost money to execute so this
824
    intrinsic cost is for the operations that need to be paid for as part of
825
    the transaction. Data transfer, for example, is part of this intrinsic
826
    cost. It costs ether to send data over the wire and that ether is
827
    accounted for in the intrinsic cost calculated in this function. This
828
    intrinsic cost must be calculated and paid for before execution in order
829
    for all operations to be implemented.
830
831
    Parameters
832
    ----------
833
    tx :
834
        Transaction to compute the intrinsic cost of.
835
836
    Returns
837
    -------
838
    verified : `ethereum.base_types.Uint`
839
        The intrinsic cost of the transaction.
840
    """
841
    data_cost = 0
842
843
    for byte in tx.data:
844
        if byte == 0:
845
            data_cost += TX_DATA_COST_PER_ZERO
846
        else:
847
            data_cost += TX_DATA_COST_PER_NON_ZERO
848
849
    if tx.to == Bytes0(b""):
850
        create_cost = TX_CREATE_COST + int(init_code_cost(Uint(len(tx.data))))
851
    else:
852
        create_cost = 0
853
854
    access_list_cost = 0
755
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
855
    if isinstance(
856
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
857
    ):
858
        for _address, keys in tx.access_list:
859
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
860
            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
861
862
    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:
866
    """
867
    Extracts the sender address from a transaction.
868
869
    The v, r, and s values are the three parts that make up the signature
870
    of a transaction. In order to recover the sender of a transaction the two
871
    components needed are the signature (``v``, ``r``, and ``s``) and the
872
    signing hash of the transaction. The sender's public key can be obtained
873
    with these two values and therefore the sender address can be retrieved.
874
875
    Parameters
876
    ----------
877
    tx :
878
        Transaction of interest.
879
    chain_id :
880
        ID of the executing chain.
881
882
    Returns
883
    -------
884
    sender : `ethereum.fork_types.Address`
885
        The address of the account that signed the transaction.
886
    """
887
    r, s = tx.r, tx.s
888
    if U256(0) >= r or r >= SECP256K1N:
889
        raise InvalidBlock
890
    if U256(0) >= s or s > SECP256K1N // U256(2):
891
        raise InvalidBlock
892
893
    if isinstance(tx, LegacyTransaction):
894
        v = tx.v
895
        if v == 27 or v == 28:
896
            public_key = secp256k1_recover(
897
                r, s, v - U256(27), signing_hash_pre155(tx)
898
            )
899
        else:
900
            chain_id_x2 = U256(chain_id) * U256(2)
901
            if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
902
                raise InvalidBlock
903
            public_key = secp256k1_recover(
904
                r,
905
                s,
906
                v - U256(35) - chain_id_x2,
907
                signing_hash_155(tx, chain_id),
908
            )
909
    elif isinstance(tx, AccessListTransaction):
910
        public_key = secp256k1_recover(
911
            r, s, tx.y_parity, signing_hash_2930(tx)
912
        )
913
    elif isinstance(tx, FeeMarketTransaction):
914
        public_key = secp256k1_recover(
915
            r, s, tx.y_parity, signing_hash_1559(tx)
814
        )
916
        )
917
    elif isinstance(tx, BlobTransaction):
918
        public_key = secp256k1_recover(
919
            r, s, tx.y_parity, signing_hash_4844(tx)
920
        )
921
922
    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:
926
    """
927
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
928
929
    Parameters
930
    ----------
931
    tx :
932
        Transaction of interest.
933
934
    Returns
935
    -------
936
    hash : `ethereum.crypto.hash.Hash32`
937
        Hash of the transaction.
938
    """
939
    return keccak256(
940
        rlp.encode(
941
            (
942
                tx.nonce,
943
                tx.gas_price,
944
                tx.gas,
945
                tx.to,
946
                tx.value,
947
                tx.data,
948
            )
949
        )
950
    )

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:
954
    """
955
    Compute the hash of a transaction used in a EIP 155 signature.
956
957
    Parameters
958
    ----------
959
    tx :
960
        Transaction of interest.
961
    chain_id :
962
        The id of the current chain.
963
964
    Returns
965
    -------
966
    hash : `ethereum.crypto.hash.Hash32`
967
        Hash of the transaction.
968
    """
969
    return keccak256(
970
        rlp.encode(
971
            (
972
                tx.nonce,
973
                tx.gas_price,
974
                tx.gas,
975
                tx.to,
976
                tx.value,
977
                tx.data,
978
                chain_id,
979
                Uint(0),
980
                Uint(0),
981
            )
982
        )
983
    )

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:
987
    """
988
    Compute the hash of a transaction used in a EIP 2930 signature.
989
990
    Parameters
991
    ----------
992
    tx :
993
        Transaction of interest.
994
995
    Returns
996
    -------
997
    hash : `ethereum.crypto.hash.Hash32`
998
        Hash of the transaction.
999
    """
1000
    return keccak256(
1001
        b"\x01"
1002
        + rlp.encode(
1003
            (
1004
                tx.chain_id,
1005
                tx.nonce,
1006
                tx.gas_price,
1007
                tx.gas,
1008
                tx.to,
1009
                tx.value,
1010
                tx.data,
1011
                tx.access_list,
1012
            )
1013
        )
1014
    )

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:
1018
    """
1019
    Compute the hash of a transaction used in a EIP 1559 signature.
1020
1021
    Parameters
1022
    ----------
1023
    tx :
1024
        Transaction of interest.
1025
1026
    Returns
1027
    -------
1028
    hash : `ethereum.crypto.hash.Hash32`
1029
        Hash of the transaction.
1030
    """
1031
    return keccak256(
1032
        b"\x02"
1033
        + rlp.encode(
1034
            (
1035
                tx.chain_id,
1036
                tx.nonce,
1037
                tx.max_priority_fee_per_gas,
1038
                tx.max_fee_per_gas,
1039
                tx.gas,
1040
                tx.to,
1041
                tx.value,
1042
                tx.data,
1043
                tx.access_list,
1044
            )
1045
        )
1046
    )

signing_hash_4844

Compute the hash of a transaction used in a EIP-4844 signature.

Parameters

tx : Transaction of interest.

Returns

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

def signing_hash_4844(tx: BlobTransaction) -> Hash32:
1050
    """
1051
    Compute the hash of a transaction used in a EIP-4844 signature.
1052
1053
    Parameters
1054
    ----------
1055
    tx :
1056
        Transaction of interest.
1057
1058
    Returns
1059
    -------
1060
    hash : `ethereum.crypto.hash.Hash32`
1061
        Hash of the transaction.
1062
    """
1063
    return keccak256(
1064
        b"\x03"
1065
        + rlp.encode(
1066
            (
1067
                tx.chain_id,
1068
                tx.nonce,
1069
                tx.max_priority_fee_per_gas,
1070
                tx.max_fee_per_gas,
1071
                tx.gas,
1072
                tx.to,
1073
                tx.value,
1074
                tx.data,
1075
                tx.access_list,
1076
                tx.max_fee_per_blob_gas,
1077
                tx.blob_versioned_hashes,
1078
            )
1079
        )
1080
    )

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:
1084
    """
1085
    Computes the hash of a block header.
1086
1087
    The header hash of a block is the canonical hash that is used to refer
1088
    to a specific block and completely distinguishes a block from another.
1089
1090
    ``keccak256`` is a function that produces a 256 bit hash of any input.
1091
    It also takes in any number of bytes as an input and produces a single
1092
    hash for them. A hash is a completely unique output for a single input.
1093
    So an input corresponds to one unique hash that can be used to identify
1094
    the input exactly.
1095
1096
    Prior to using the ``keccak256`` hash function, the header must be
1097
    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
1098
    RLP encoding the header converts it into a space-efficient format that
1099
    allows for easy transfer of data between nodes. The purpose of RLP is to
1100
    encode arbitrarily nested arrays of binary data, and RLP is the primary
1101
    encoding method used to serialize objects in Ethereum's execution layer.
1102
    The only purpose of RLP is to encode structure; encoding specific data
1103
    types (e.g. strings, floats) is left up to higher-order protocols.
1104
1105
    Parameters
1106
    ----------
1107
    header :
1108
        Header of interest.
1109
1110
    Returns
1111
    -------
1112
    hash : `ethereum.crypto.hash.Hash32`
1113
        Hash of the header.
1114
    """
1115
    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:
1119
    """
1120
    Validates the gas limit for a block.
1121
1122
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
1123
    quotient of the parent block's gas limit and the
1124
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
1125
    passed through as a parameter is greater than or equal to the *sum* of
1126
    the parent's gas and the adjustment delta then the limit for gas is too
1127
    high and fails this function's check. Similarly, if the limit is less
1128
    than or equal to the *difference* of the parent's gas and the adjustment
1129
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
1130
    check fails because the gas limit doesn't allow for a sufficient or
1131
    reasonable amount of gas to be used on a block.
1132
1133
    Parameters
1134
    ----------
1135
    gas_limit :
1136
        Gas limit to validate.
1137
1138
    parent_gas_limit :
1139
        Gas limit of the parent block.
1140
1141
    Returns
1142
    -------
1143
    check : `bool`
1144
        True if gas limit constraints are satisfied, False otherwise.
1145
    """
1146
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
1147
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
1148
        return False
1149
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
1150
        return False
1151
    if gas_limit < GAS_LIMIT_MINIMUM:
1152
        return False
1153
1154
    return True