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

69
BASE_FEE_MAX_CHANGE_DENOMINATOR = 8

ELASTICITY_MULTIPLIER

70
ELASTICITY_MULTIPLIER = 2

GAS_LIMIT_ADJUSTMENT_FACTOR

71
GAS_LIMIT_ADJUSTMENT_FACTOR = 1024

GAS_LIMIT_MINIMUM

72
GAS_LIMIT_MINIMUM = 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 = 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
    if apply_body_output.transactions_root != block.header.transactions_root:
204
        raise InvalidBlock
205
    if apply_body_output.state_root != block.header.state_root:
206
        raise InvalidBlock
207
    if apply_body_output.receipt_root != block.header.receipt_root:
208
        raise InvalidBlock
209
    if apply_body_output.block_logs_bloom != block.header.bloom:
210
        raise InvalidBlock
211
    if apply_body_output.withdrawals_root != block.header.withdrawals_root:
212
        raise InvalidBlock
213
    if apply_body_output.blob_gas_used != block.header.blob_gas_used:
214
        raise InvalidBlock
215
216
    chain.blocks.append(block)
217
    if len(chain.blocks) > 255:
218
        # Real clients have to store more blocks to deal with reorgs, but the
219
        # protocol only requires the last 255
220
        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:
229
    """
230
    Calculates the base fee per gas for the block.
231
232
    Parameters
233
    ----------
234
    block_gas_limit :
235
        Gas limit of the block for which the base fee is being calculated.
236
    parent_gas_limit :
237
        Gas limit of the parent block.
238
    parent_gas_used :
239
        Gas used in the parent block.
240
    parent_base_fee_per_gas :
241
        Base fee per gas of the parent block.
242
243
    Returns
244
    -------
245
    base_fee_per_gas : `Uint`
246
        Base fee per gas for the block.
247
    """
248
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
249
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
250
        raise InvalidBlock
251
252
    if parent_gas_used == parent_gas_target:
253
        expected_base_fee_per_gas = parent_base_fee_per_gas
254
    elif parent_gas_used > parent_gas_target:
255
        gas_used_delta = parent_gas_used - parent_gas_target
256
257
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
258
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
259
260
        base_fee_per_gas_delta = max(
261
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
262
            1,
263
        )
264
265
        expected_base_fee_per_gas = (
266
            parent_base_fee_per_gas + base_fee_per_gas_delta
267
        )
268
    else:
269
        gas_used_delta = parent_gas_target - parent_gas_used
270
271
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
272
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
273
274
        base_fee_per_gas_delta = (
275
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
276
        )
277
278
        expected_base_fee_per_gas = (
279
            parent_base_fee_per_gas - base_fee_per_gas_delta
280
        )
281
282
    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:
286
    """
287
    Verifies a block header.
288
289
    In order to consider a block's header valid, the logic for the
290
    quantities in the header should match the logic for the block itself.
291
    For example the header timestamp should be greater than the block's parent
292
    timestamp because the block was created *after* the parent block.
293
    Additionally, the block's number should be directly following the parent
294
    block's number since it is the next block in the sequence.
295
296
    Parameters
297
    ----------
298
    header :
299
        Header to check for correctness.
300
    parent_header :
301
        Parent Header of the header to check for correctness
302
    """
303
    if header.gas_used > header.gas_limit:
304
        raise InvalidBlock
305
306
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
307
        header.gas_limit,
308
        parent_header.gas_limit,
309
        parent_header.gas_used,
310
        parent_header.base_fee_per_gas,
311
    )
312
    if expected_base_fee_per_gas != header.base_fee_per_gas:
313
        raise InvalidBlock
314
    if header.timestamp <= parent_header.timestamp:
315
        raise InvalidBlock
316
    if header.number != parent_header.number + 1:
317
        raise InvalidBlock
318
    if len(header.extra_data) > 32:
319
        raise InvalidBlock
320
    if header.difficulty != 0:
321
        raise InvalidBlock
322
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
323
        raise InvalidBlock
324
    if header.ommers_hash != EMPTY_OMMER_HASH:
325
        raise InvalidBlock
326
327
    block_parent_hash = keccak256(rlp.encode(parent_header))
328
    if header.parent_hash != block_parent_hash:
329
        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, ...]]:
340
    """
341
    Check if the transaction is includable in the block.
342
343
    Parameters
344
    ----------
345
    state :
346
        Current state.
347
    tx :
348
        The transaction.
319
    base_fee_per_gas :
320
        The block base fee.
349
    gas_available :
350
        The gas remaining in the block.
351
    chain_id :
352
        The ID of the current chain.
353
    base_fee_per_gas :
354
        The block base fee.
355
    excess_blob_gas :
356
        The excess blob gas.
357
358
    Returns
359
    -------
360
    sender_address :
361
        The sender of the transaction.
362
    effective_gas_price :
363
        The price to charge for gas when the transaction is executed.
364
    blob_versioned_hashes :
365
        The blob versioned hashes of the transaction.
366
367
    Raises
368
    ------
369
    InvalidBlock :
370
        If the transaction is not includable.
371
    """
372
    if calculate_intrinsic_cost(tx) > tx.gas:
373
        raise InvalidBlock
374
    if tx.nonce >= 2**64 - 1:
375
        raise InvalidBlock
376
    if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE:
377
        raise InvalidBlock
378
379
    if tx.gas > gas_available:
380
        raise InvalidBlock
340
    sender_address = recover_sender(chain_id, tx)
381
342
    if isinstance(tx, FeeMarketTransaction):
382
    sender = recover_sender(chain_id, tx)
383
    sender_account = get_account(state, sender)
384
385
    if isinstance(tx, (FeeMarketTransaction, BlobTransaction)):
386
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
387
            raise InvalidBlock
388
        if tx.max_fee_per_gas < base_fee_per_gas:
389
            raise InvalidBlock
390
391
        priority_fee_per_gas = min(
392
            tx.max_priority_fee_per_gas,
393
            tx.max_fee_per_gas - base_fee_per_gas,
394
        )
352
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
395
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
396
        max_gas_fee = tx.gas * tx.max_fee_per_gas
397
    else:
398
        if tx.gas_price < base_fee_per_gas:
399
            raise InvalidBlock
356
        effective_gas_price = tx.gas_price
400
        effective_gas_price = tx.gas_price
401
        max_gas_fee = tx.gas * tx.gas_price
402
358
    return sender_address, effective_gas_price
403
    if isinstance(tx, BlobTransaction):
404
        if not isinstance(tx.to, Address):
405
            raise InvalidBlock
406
        if len(tx.blob_versioned_hashes) == 0:
407
            raise InvalidBlock
408
        for blob_versioned_hash in tx.blob_versioned_hashes:
409
            if blob_versioned_hash[0:1] != VERSIONED_HASH_VERSION_KZG:
410
                raise InvalidBlock
411
412
        if tx.max_fee_per_blob_gas < calculate_blob_gas_price(excess_blob_gas):
413
            raise InvalidBlock
414
415
        max_gas_fee += calculate_total_blob_gas(tx) * tx.max_fee_per_blob_gas
416
        blob_versioned_hashes = tx.blob_versioned_hashes
417
    else:
418
        blob_versioned_hashes = ()
419
    if sender_account.nonce != tx.nonce:
420
        raise InvalidBlock
421
    if sender_account.balance < max_gas_fee + tx.value:
422
        raise InvalidBlock
423
    if sender_account.code != bytearray():
424
        raise InvalidBlock
425
426
    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]:
435
    """
436
    Make the receipt for a transaction that was executed.
437
438
    Parameters
439
    ----------
440
    tx :
441
        The executed transaction.
442
    error :
443
        Error in the top level frame of the transaction, if any.
444
    cumulative_gas_used :
445
        The total gas used so far in the block after the transaction was
446
        executed.
447
    logs :
448
        The logs produced by the transaction.
449
450
    Returns
451
    -------
452
    receipt :
453
        The receipt for the transaction.
454
    """
455
    receipt = Receipt(
456
        succeeded=error is None,
457
        cumulative_gas_used=cumulative_gas_used,
458
        bloom=logs_bloom(logs),
459
        logs=logs,
460
    )
461
462
    if isinstance(tx, AccessListTransaction):
463
        return b"\x01" + rlp.encode(receipt)
464
    elif isinstance(tx, FeeMarketTransaction):
465
        return b"\x02" + rlp.encode(receipt)
398
    else:
399
        return receipt
466
    elif isinstance(tx, BlobTransaction):
467
        return b"\x03" + rlp.encode(receipt)
468
    else:
469
        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.

472
@dataclass
class ApplyBodyOutput:

block_gas_used

496
    block_gas_used: Uint

transactions_root

497
    transactions_root: Root

receipt_root

498
    receipt_root: Root

block_logs_bloom

499
    block_logs_bloom: Bloom

state_root

500
    state_root: Root

withdrawals_root

501
    withdrawals_root: Root

blob_gas_used

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

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]]:
707
    """
708
    Execute a transaction against the provided environment.
709
710
    This function processes the actions needed to execute a transaction.
711
    It decrements the sender's account after calculating the gas fee and
712
    refunds them the proper amount after execution. Calling contracts,
713
    deploying code, and incrementing nonces are all examples of actions that
714
    happen within this function or from a call made within this function.
715
716
    Accounts that are marked for deletion are processed and destroyed after
717
    execution.
718
719
    Parameters
720
    ----------
721
    env :
722
        Environment for the Ethereum Virtual Machine.
723
    tx :
724
        Transaction to execute.
725
726
    Returns
727
    -------
728
    gas_left : `ethereum.base_types.U256`
729
        Remaining gas after execution.
730
    logs : `Tuple[ethereum.blocks.Log, ...]`
731
        Logs generated during execution.
732
    """
592
    if not validate_transaction(tx):
593
        raise InvalidBlock
594
733
    sender = env.origin
734
    sender_account = get_account(env.state, sender)
735
598
    if isinstance(tx, FeeMarketTransaction):
599
        max_gas_fee = tx.gas * tx.max_fee_per_gas
736
    if isinstance(tx, BlobTransaction):
737
        blob_gas_fee = calculate_data_fee(env.excess_blob_gas, tx)
738
    else:
601
        max_gas_fee = tx.gas * tx.gas_price
602
    if sender_account.nonce != tx.nonce:
603
        raise InvalidBlock
604
    if sender_account.balance < max_gas_fee + tx.value:
605
        raise InvalidBlock
606
    if sender_account.code != bytearray():
607
        raise InvalidBlock
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
614
    sender_balance_after_gas_fee = sender_account.balance - effective_gas_fee
746
    sender_balance_after_gas_fee = (
747
        sender_account.balance - effective_gas_fee - blob_gas_fee
748
    )
749
    set_account_balance(env.state, sender, sender_balance_after_gas_fee)
750
751
    preaccessed_addresses = set()
752
    preaccessed_storage_keys = set()
753
    preaccessed_addresses.add(env.coinbase)
620
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
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 // 5, 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 = (
789
        get_account(env.state, sender).balance + gas_refund_amount
790
    )
791
    set_account_balance(env.state, sender, sender_balance_after_refund)
792
793
    # transfer miner fees
794
    coinbase_balance_after_mining_fee = (
795
        get_account(env.state, env.coinbase).balance + transaction_fee
796
    )
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
671
    for address in output.touched_accounts:
672
        if account_exists_and_is_empty(env.state, address):
673
            destroy_account(env.state, address)
807
    destroy_touched_empty_accounts(env.state, output.touched_accounts)
808
809
    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:
679
    """
680
    Verifies a transaction.
681
682
    The gas in a transaction gets used to pay for the intrinsic cost of
683
    operations, therefore if there is insufficient gas then it would not
684
    be possible to execute a transaction and it will be declared invalid.
685
686
    Additionally, the nonce of a transaction must not equal or exceed the
687
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
688
    In practice, defining the limit as ``2**64-1`` has no impact because
689
    sending ``2**64-1`` transactions is improbable. It's not strictly
690
    impossible though, ``2**64-1`` transactions is the entire capacity of the
691
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
692
693
    Parameters
694
    ----------
695
    tx :
696
        Transaction to validate.
697
698
    Returns
699
    -------
700
    verified : `bool`
701
        True if the transaction can be executed, or False otherwise.
702
    """
703
    if calculate_intrinsic_cost(tx) > tx.gas:
704
        return False
705
    if tx.nonce >= 2**64 - 1:
706
        return False
707
    if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE:
708
        return False
709
710
    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:
813
    """
814
    Calculates the gas that is charged before execution is started.
815
816
    The intrinsic cost of the transaction is charged before execution has
817
    begun. Functions/operations in the EVM cost money to execute so this
818
    intrinsic cost is for the operations that need to be paid for as part of
819
    the transaction. Data transfer, for example, is part of this intrinsic
820
    cost. It costs ether to send data over the wire and that ether is
821
    accounted for in the intrinsic cost calculated in this function. This
822
    intrinsic cost must be calculated and paid for before execution in order
823
    for all operations to be implemented.
824
825
    Parameters
826
    ----------
827
    tx :
828
        Transaction to compute the intrinsic cost of.
829
830
    Returns
831
    -------
832
    verified : `ethereum.base_types.Uint`
833
        The intrinsic cost of the transaction.
834
    """
835
    data_cost = 0
836
837
    for byte in tx.data:
838
        if byte == 0:
839
            data_cost += TX_DATA_COST_PER_ZERO
840
        else:
841
            data_cost += TX_DATA_COST_PER_NON_ZERO
842
843
    if tx.to == Bytes0(b""):
844
        create_cost = TX_CREATE_COST + int(init_code_cost(Uint(len(tx.data))))
845
    else:
846
        create_cost = 0
847
848
    access_list_cost = 0
750
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
849
    if isinstance(
850
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
851
    ):
852
        for _address, keys in tx.access_list:
853
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
854
            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
855
856
    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:
860
    """
861
    Extracts the sender address from a transaction.
862
863
    The v, r, and s values are the three parts that make up the signature
864
    of a transaction. In order to recover the sender of a transaction the two
865
    components needed are the signature (``v``, ``r``, and ``s``) and the
866
    signing hash of the transaction. The sender's public key can be obtained
867
    with these two values and therefore the sender address can be retrieved.
868
869
    Parameters
870
    ----------
871
    tx :
872
        Transaction of interest.
873
    chain_id :
874
        ID of the executing chain.
875
876
    Returns
877
    -------
878
    sender : `ethereum.fork_types.Address`
879
        The address of the account that signed the transaction.
880
    """
881
    r, s = tx.r, tx.s
882
    if 0 >= r or r >= SECP256K1N:
883
        raise InvalidBlock
884
    if 0 >= s or s > SECP256K1N // 2:
885
        raise InvalidBlock
886
887
    if isinstance(tx, LegacyTransaction):
888
        v = tx.v
889
        if v == 27 or v == 28:
890
            public_key = secp256k1_recover(
891
                r, s, v - 27, signing_hash_pre155(tx)
892
            )
893
        else:
894
            if v != 35 + chain_id * 2 and v != 36 + chain_id * 2:
895
                raise InvalidBlock
896
            public_key = secp256k1_recover(
897
                r, s, v - 35 - chain_id * 2, signing_hash_155(tx, chain_id)
898
            )
899
    elif isinstance(tx, AccessListTransaction):
900
        public_key = secp256k1_recover(
901
            r, s, tx.y_parity, signing_hash_2930(tx)
902
        )
903
    elif isinstance(tx, FeeMarketTransaction):
904
        public_key = secp256k1_recover(
905
            r, s, tx.y_parity, signing_hash_1559(tx)
805
        )
906
        )
907
    elif isinstance(tx, BlobTransaction):
908
        public_key = secp256k1_recover(
909
            r, s, tx.y_parity, signing_hash_4844(tx)
910
        )
911
912
    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:
916
    """
917
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
918
919
    Parameters
920
    ----------
921
    tx :
922
        Transaction of interest.
923
924
    Returns
925
    -------
926
    hash : `ethereum.crypto.hash.Hash32`
927
        Hash of the transaction.
928
    """
929
    return keccak256(
930
        rlp.encode(
931
            (
932
                tx.nonce,
933
                tx.gas_price,
934
                tx.gas,
935
                tx.to,
936
                tx.value,
937
                tx.data,
938
            )
939
        )
940
    )

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:
944
    """
945
    Compute the hash of a transaction used in a EIP 155 signature.
946
947
    Parameters
948
    ----------
949
    tx :
950
        Transaction of interest.
951
    chain_id :
952
        The id of the current chain.
953
954
    Returns
955
    -------
956
    hash : `ethereum.crypto.hash.Hash32`
957
        Hash of the transaction.
958
    """
959
    return keccak256(
960
        rlp.encode(
961
            (
962
                tx.nonce,
963
                tx.gas_price,
964
                tx.gas,
965
                tx.to,
966
                tx.value,
967
                tx.data,
968
                chain_id,
969
                Uint(0),
970
                Uint(0),
971
            )
972
        )
973
    )

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:
977
    """
978
    Compute the hash of a transaction used in a EIP 2930 signature.
979
980
    Parameters
981
    ----------
982
    tx :
983
        Transaction of interest.
984
985
    Returns
986
    -------
987
    hash : `ethereum.crypto.hash.Hash32`
988
        Hash of the transaction.
989
    """
990
    return keccak256(
991
        b"\x01"
992
        + rlp.encode(
993
            (
994
                tx.chain_id,
995
                tx.nonce,
996
                tx.gas_price,
997
                tx.gas,
998
                tx.to,
999
                tx.value,
1000
                tx.data,
1001
                tx.access_list,
1002
            )
1003
        )
1004
    )

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:
1008
    """
1009
    Compute the hash of a transaction used in a EIP 1559 signature.
1010
1011
    Parameters
1012
    ----------
1013
    tx :
1014
        Transaction of interest.
1015
1016
    Returns
1017
    -------
1018
    hash : `ethereum.crypto.hash.Hash32`
1019
        Hash of the transaction.
1020
    """
1021
    return keccak256(
1022
        b"\x02"
1023
        + rlp.encode(
1024
            (
1025
                tx.chain_id,
1026
                tx.nonce,
1027
                tx.max_priority_fee_per_gas,
1028
                tx.max_fee_per_gas,
1029
                tx.gas,
1030
                tx.to,
1031
                tx.value,
1032
                tx.data,
1033
                tx.access_list,
1034
            )
1035
        )
1036
    )

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:
1040
    """
1041
    Compute the hash of a transaction used in a EIP-4844 signature.
1042
1043
    Parameters
1044
    ----------
1045
    tx :
1046
        Transaction of interest.
1047
1048
    Returns
1049
    -------
1050
    hash : `ethereum.crypto.hash.Hash32`
1051
        Hash of the transaction.
1052
    """
1053
    return keccak256(
1054
        b"\x03"
1055
        + rlp.encode(
1056
            (
1057
                tx.chain_id,
1058
                tx.nonce,
1059
                tx.max_priority_fee_per_gas,
1060
                tx.max_fee_per_gas,
1061
                tx.gas,
1062
                tx.to,
1063
                tx.value,
1064
                tx.data,
1065
                tx.access_list,
1066
                tx.max_fee_per_blob_gas,
1067
                tx.blob_versioned_hashes,
1068
            )
1069
        )
1070
    )

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