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

80
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

81
ELASTICITY_MULTIPLIER = Uint(2)

GAS_LIMIT_ADJUSTMENT_FACTOR

82
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

83
GAS_LIMIT_MINIMUM = Uint(5000)

EMPTY_OMMER_HASH

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

SYSTEM_ADDRESS

85
SYSTEM_ADDRESS = hex_to_address("0xfffffffffffffffffffffffffffffffffffffffe")

BEACON_ROOTS_ADDRESS

86
BEACON_ROOTS_ADDRESS = hex_to_address(
87
    "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"
88
)

SYSTEM_TRANSACTION_GAS

89
SYSTEM_TRANSACTION_GAS = Uint(30000000)

MAX_BLOB_GAS_PER_BLOCK

90
MAX_BLOB_GAS_PER_BLOCK = U64(786432)

VERSIONED_HASH_VERSION_KZG

91
VERSIONED_HASH_VERSION_KZG = b"\x01"

BlockChain

History and current state of the block chain.

94
@dataclass
class BlockChain:

blocks

100
    blocks: List[Block]

state

101
    state: State

chain_id

102
    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:
106
    """
107
    Transforms the state from the previous hard fork (`old`) into the block
108
    chain object for this hard fork and returns it.
109
110
    When forks need to implement an irregular state transition, this function
111
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
112
    an example.
113
114
    Parameters
115
    ----------
116
    old :
117
        Previous block chain object.
118
119
    Returns
120
    -------
121
    new : `BlockChain`
122
        Upgraded block chain object for this hard fork.
123
    """
124
    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]:
128
    """
129
    Obtain the list of hashes of the previous 256 blocks in order of
130
    increasing block number.
131
132
    This function will return less hashes for the first 256 blocks.
133
134
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
135
    therefore this function retrieves them.
136
137
    Parameters
138
    ----------
139
    chain :
140
        History and current state.
141
142
    Returns
143
    -------
144
    recent_block_hashes : `List[Hash32]`
145
        Hashes of the recent 256 blocks in order of increasing block number.
146
    """
147
    recent_blocks = chain.blocks[-255:]
148
    # TODO: This function has not been tested rigorously
149
    if len(recent_blocks) == 0:
150
        return []
151
152
    recent_block_hashes = []
153
154
    for block in recent_blocks:
155
        prev_block_hash = block.header.parent_hash
156
        recent_block_hashes.append(prev_block_hash)
157
158
    # We are computing the hash only for the most recent block and not for
159
    # the rest of the blocks as they have successors which have the hash of
160
    # the current block as parent hash.
161
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
162
    recent_block_hashes.append(most_recent_block_hash)
163
164
    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:
168
    """
169
    Attempts to apply a block to an existing block chain.
170
171
    All parts of the block's contents need to be verified before being added
172
    to the chain. Blocks are verified by ensuring that the contents of the
173
    block make logical sense with the contents of the parent block. The
174
    information in the block's header must also match the corresponding
175
    information in the block.
176
177
    To implement Ethereum, in theory clients are only required to store the
178
    most recent 255 blocks of the chain since as far as execution is
179
    concerned, only those blocks are accessed. Practically, however, clients
180
    should store more blocks to handle reorgs.
181
182
    Parameters
183
    ----------
184
    chain :
185
        History and current state.
186
    block :
187
        Block to apply to `chain`.
188
    """
189
    validate_header(chain, block.header)
190
    if block.ommers != ():
191
        raise InvalidBlock
192
193
    block_env = vm.BlockEnvironment(
194
        chain_id=chain.chain_id,
195
        state=chain.state,
196
        block_gas_limit=block.header.gas_limit,
197
        block_hashes=get_last_256_block_hashes(chain),
198
        coinbase=block.header.coinbase,
199
        number=block.header.number,
200
        base_fee_per_gas=block.header.base_fee_per_gas,
201
        time=block.header.timestamp,
202
        prev_randao=block.header.prev_randao,
203
        excess_blob_gas=block.header.excess_blob_gas,
204
        parent_beacon_block_root=block.header.parent_beacon_block_root,
205
    )
206
207
    block_output = apply_body(
208
        block_env=block_env,
209
        transactions=block.transactions,
210
        withdrawals=block.withdrawals,
211
    )
212
    block_state_root = state_root(block_env.state)
213
    transactions_root = root(block_output.transactions_trie)
214
    receipt_root = root(block_output.receipts_trie)
215
    block_logs_bloom = logs_bloom(block_output.block_logs)
216
    withdrawals_root = root(block_output.withdrawals_trie)
217
218
    if block_output.block_gas_used != block.header.gas_used:
219
        raise InvalidBlock(
220
            f"{block_output.block_gas_used} != {block.header.gas_used}"
221
        )
222
    if transactions_root != block.header.transactions_root:
223
        raise InvalidBlock
224
    if block_state_root != block.header.state_root:
225
        raise InvalidBlock
226
    if receipt_root != block.header.receipt_root:
227
        raise InvalidBlock
228
    if block_logs_bloom != block.header.bloom:
229
        raise InvalidBlock
230
    if withdrawals_root != block.header.withdrawals_root:
231
        raise InvalidBlock
232
    if block_output.blob_gas_used != block.header.blob_gas_used:
233
        raise InvalidBlock
234
235
    chain.blocks.append(block)
236
    if len(chain.blocks) > 255:
237
        # Real clients have to store more blocks to deal with reorgs, but the
238
        # protocol only requires the last 255
239
        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:
248
    """
249
    Calculates the base fee per gas for the block.
250
251
    Parameters
252
    ----------
253
    block_gas_limit :
254
        Gas limit of the block for which the base fee is being calculated.
255
    parent_gas_limit :
256
        Gas limit of the parent block.
257
    parent_gas_used :
258
        Gas used in the parent block.
259
    parent_base_fee_per_gas :
260
        Base fee per gas of the parent block.
261
262
    Returns
263
    -------
264
    base_fee_per_gas : `Uint`
265
        Base fee per gas for the block.
266
    """
267
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
268
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
269
        raise InvalidBlock
270
271
    if parent_gas_used == parent_gas_target:
272
        expected_base_fee_per_gas = parent_base_fee_per_gas
273
    elif parent_gas_used > parent_gas_target:
274
        gas_used_delta = parent_gas_used - parent_gas_target
275
276
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
277
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
278
279
        base_fee_per_gas_delta = max(
280
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
281
            Uint(1),
282
        )
283
284
        expected_base_fee_per_gas = (
285
            parent_base_fee_per_gas + base_fee_per_gas_delta
286
        )
287
    else:
288
        gas_used_delta = parent_gas_target - parent_gas_used
289
290
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
291
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
292
293
        base_fee_per_gas_delta = (
294
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
295
        )
296
297
        expected_base_fee_per_gas = (
298
            parent_base_fee_per_gas - base_fee_per_gas_delta
299
        )
300
301
    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

chain : History and current state. header : Header to check for correctness.

def validate_header(chain: BlockChain, ​​header: Header) -> None:
305
    """
306
    Verifies a block header.
307
308
    In order to consider a block's header valid, the logic for the
309
    quantities in the header should match the logic for the block itself.
310
    For example the header timestamp should be greater than the block's parent
311
    timestamp because the block was created *after* the parent block.
312
    Additionally, the block's number should be directly following the parent
313
    block's number since it is the next block in the sequence.
314
315
    Parameters
316
    ----------
317
    chain :
318
        History and current state.
319
    header :
320
        Header to check for correctness.
321
    """
322
    if header.number < Uint(1):
323
        raise InvalidBlock
324
325
    parent_header = chain.blocks[-1].header
326
327
    excess_blob_gas = calculate_excess_blob_gas(parent_header)
328
    if header.excess_blob_gas != excess_blob_gas:
329
        raise InvalidBlock
330
331
    if header.gas_used > header.gas_limit:
332
        raise InvalidBlock
333
334
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
335
        header.gas_limit,
336
        parent_header.gas_limit,
337
        parent_header.gas_used,
338
        parent_header.base_fee_per_gas,
339
    )
340
    if expected_base_fee_per_gas != header.base_fee_per_gas:
341
        raise InvalidBlock
342
    if header.timestamp <= parent_header.timestamp:
343
        raise InvalidBlock
344
    if header.number != parent_header.number + Uint(1):
345
        raise InvalidBlock
346
    if len(header.extra_data) > 32:
347
        raise InvalidBlock
348
    if header.difficulty != 0:
349
        raise InvalidBlock
350
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
351
        raise InvalidBlock
352
    if header.ommers_hash != EMPTY_OMMER_HASH:
353
        raise InvalidBlock
354
355
    block_parent_hash = keccak256(rlp.encode(parent_header))
356
    if header.parent_hash != block_parent_hash:
357
        raise InvalidBlock

check_transaction

Check if the transaction is includable in the block.

Parameters

block_env : The block scoped environment. block_output : The block output for the current block. tx : The transaction.

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. tx_blob_gas_used: The blob gas used by the transaction.

Raises

InvalidBlock : If the transaction is not includable. GasUsedExceedsLimitError : If the gas used by the transaction exceeds the block's gas limit. NonceMismatchError : If the nonce of the transaction is not equal to the sender's nonce. InsufficientBalanceError : If the sender's balance is not enough to pay for the transaction. InvalidSenderError : If the transaction is from an address that does not exist anymore. PriorityFeeGreaterThanMaxFeeError : If the priority fee is greater than the maximum fee per gas. InsufficientMaxFeePerGasError : If the maximum fee per gas is insufficient for the transaction. InsufficientMaxFeePerBlobGasError : If the maximum fee per blob gas is insufficient for the transaction. BlobGasLimitExceededError : If the blob gas used by the transaction exceeds the block's blob gas limit. InvalidBlobVersionedHashError : If the transaction contains a blob versioned hash with an invalid version. NoBlobDataError : If the transaction is a type 3 but has no blobs. TransactionTypeContractCreationError: If the transaction type is not allowed to create contracts.

def check_transaction(block_env: ethereum.shanghai.vm.BlockEnvironmentethereum.cancun.vm.BlockEnvironment, ​​block_output: ethereum.shanghai.vm.BlockOutputethereum.cancun.vm.BlockOutput, ​​tx: Transaction) -> Tuple[Address, Uint, Tuple[VersionedHash, ...]U64]:
365
    """
366
    Check if the transaction is includable in the block.
367
368
    Parameters
369
    ----------
370
    block_env :
371
        The block scoped environment.
372
    block_output :
373
        The block output for the current block.
374
    tx :
375
        The transaction.
376
377
    Returns
378
    -------
379
    sender_address :
380
        The sender of the transaction.
381
    effective_gas_price :
382
        The price to charge for gas when the transaction is executed.
383
    blob_versioned_hashes :
384
        The blob versioned hashes of the transaction.
385
    tx_blob_gas_used:
386
        The blob gas used by the transaction.
387
388
    Raises
389
    ------
390
    InvalidBlock :
391
        If the transaction is not includable.
392
    GasUsedExceedsLimitError :
393
        If the gas used by the transaction exceeds the block's gas limit.
394
    NonceMismatchError :
395
        If the nonce of the transaction is not equal to the sender's nonce.
396
    InsufficientBalanceError :
397
        If the sender's balance is not enough to pay for the transaction.
398
    InvalidSenderError :
399
        If the transaction is from an address that does not exist anymore.
400
    PriorityFeeGreaterThanMaxFeeError :
401
        If the priority fee is greater than the maximum fee per gas.
402
    InsufficientMaxFeePerGasError :
403
        If the maximum fee per gas is insufficient for the transaction.
404
    InsufficientMaxFeePerBlobGasError :
405
        If the maximum fee per blob gas is insufficient for the transaction.
406
    BlobGasLimitExceededError :
407
        If the blob gas used by the transaction exceeds the block's blob gas
408
        limit.
409
    InvalidBlobVersionedHashError :
410
        If the transaction contains a blob versioned hash with an invalid
411
        version.
412
    NoBlobDataError :
413
        If the transaction is a type 3 but has no blobs.
414
    TransactionTypeContractCreationError:
415
        If the transaction type is not allowed to create contracts.
416
    """
417
    gas_available = block_env.block_gas_limit - block_output.block_gas_used
418
    blob_gas_available = MAX_BLOB_GAS_PER_BLOCK - block_output.blob_gas_used
419
420
    if tx.gas > gas_available:
421
        raise GasUsedExceedsLimitError("gas used exceeds limit")
422
423
    tx_blob_gas_used = calculate_total_blob_gas(tx)
424
    if tx_blob_gas_used > blob_gas_available:
425
        raise BlobGasLimitExceededError("blob gas limit exceeded")
426
427
    sender_address = recover_sender(block_env.chain_id, tx)
428
    sender_account = get_account(block_env.state, sender_address)
429
377
    if isinstance(tx, FeeMarketTransaction):
430
    if isinstance(tx, (FeeMarketTransaction, BlobTransaction)):
431
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
432
            raise PriorityFeeGreaterThanMaxFeeError(
433
                "priority fee greater than max fee"
434
            )
435
        if tx.max_fee_per_gas < block_env.base_fee_per_gas:
436
            raise InsufficientMaxFeePerGasError(
437
                tx.max_fee_per_gas, block_env.base_fee_per_gas
438
            )
439
440
        priority_fee_per_gas = min(
441
            tx.max_priority_fee_per_gas,
442
            tx.max_fee_per_gas - block_env.base_fee_per_gas,
443
        )
444
        effective_gas_price = priority_fee_per_gas + block_env.base_fee_per_gas
445
        max_gas_fee = tx.gas * tx.max_fee_per_gas
446
    else:
447
        if tx.gas_price < block_env.base_fee_per_gas:
448
            raise InvalidBlock
449
        effective_gas_price = tx.gas_price
450
        max_gas_fee = tx.gas * tx.gas_price
451
452
    if isinstance(tx, BlobTransaction):
453
        if not isinstance(tx.to, Address):
454
            raise TransactionTypeContractCreationError(tx)
455
        if len(tx.blob_versioned_hashes) == 0:
456
            raise NoBlobDataError("no blob data in transaction")
457
        for blob_versioned_hash in tx.blob_versioned_hashes:
458
            if blob_versioned_hash[0:1] != VERSIONED_HASH_VERSION_KZG:
459
                raise InvalidBlobVersionedHashError(
460
                    "invalid blob versioned hash"
461
                )
462
463
        blob_gas_price = calculate_blob_gas_price(block_env.excess_blob_gas)
464
        if Uint(tx.max_fee_per_blob_gas) < blob_gas_price:
465
            raise InsufficientMaxFeePerBlobGasError(
466
                "insufficient max fee per blob gas"
467
            )
468
469
        max_gas_fee += Uint(calculate_total_blob_gas(tx)) * Uint(
470
            tx.max_fee_per_blob_gas
471
        )
472
        blob_versioned_hashes = tx.blob_versioned_hashes
473
    else:
474
        blob_versioned_hashes = ()
475
    if sender_account.nonce > Uint(tx.nonce):
476
        raise NonceMismatchError("nonce too low")
477
    elif sender_account.nonce < Uint(tx.nonce):
478
        raise NonceMismatchError("nonce too high")
479
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
480
        raise InsufficientBalanceError("insufficient sender balance")
481
    if sender_account.code:
482
        raise InvalidSenderError("not EOA")
483
408
    return sender_address, effective_gas_price
484
    return (
485
        sender_address,
486
        effective_gas_price,
487
        blob_versioned_hashes,
488
        tx_blob_gas_used,
489
    )

make_receipt

Make the receipt for a transaction that was executed.

Parameters

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

Returns

receipt : The receipt for the transaction.

def make_receipt(tx: Transaction, ​​error: Optional[EthereumException], ​​cumulative_gas_used: Uint, ​​logs: Tuple[Log, ...]) -> Bytes | Receipt:
498
    """
499
    Make the receipt for a transaction that was executed.
500
501
    Parameters
502
    ----------
503
    tx :
504
        The executed transaction.
505
    error :
506
        Error in the top level frame of the transaction, if any.
507
    cumulative_gas_used :
508
        The total gas used so far in the block after the transaction was
509
        executed.
510
    logs :
511
        The logs produced by the transaction.
512
513
    Returns
514
    -------
515
    receipt :
516
        The receipt for the transaction.
517
    """
518
    receipt = Receipt(
519
        succeeded=error is None,
520
        cumulative_gas_used=cumulative_gas_used,
521
        bloom=logs_bloom(logs),
522
        logs=logs,
523
    )
524
525
    return encode_receipt(tx, receipt)

process_system_transaction

Process a system transaction with the given code.

Prefer calling process_unchecked_system_transaction unless the contract code has already been read from the state.

Parameters

block_env : The block scoped environment. target_address : Address of the contract to call. system_contract_code : Code of the contract to call. data : Data to pass to the contract.

Returns

system_tx_output : MessageCallOutput Output of processing the system transaction.

def process_system_transaction(block_env: ethereum.cancun.vm.BlockEnvironment, ​​target_address: Address, ​​system_contract_code: Bytes, ​​data: Bytes) -> MessageCallOutput:
534
    """
535
    Process a system transaction with the given code.
536
537
    Prefer calling `process_unchecked_system_transaction` unless the contract
538
    code has already been read from the state.
539
540
    Parameters
541
    ----------
542
    block_env :
543
        The block scoped environment.
544
    target_address :
545
        Address of the contract to call.
546
    system_contract_code :
547
        Code of the contract to call.
548
    data :
549
        Data to pass to the contract.
550
551
    Returns
552
    -------
553
    system_tx_output : `MessageCallOutput`
554
        Output of processing the system transaction.
555
    """
556
    tx_env = vm.TransactionEnvironment(
557
        origin=SYSTEM_ADDRESS,
558
        gas_price=block_env.base_fee_per_gas,
559
        gas=SYSTEM_TRANSACTION_GAS,
560
        access_list_addresses=set(),
561
        access_list_storage_keys=set(),
562
        transient_storage=TransientStorage(),
563
        blob_versioned_hashes=(),
564
        index_in_block=None,
565
        tx_hash=None,
566
        traces=[],
567
    )
568
569
    system_tx_message = Message(
570
        block_env=block_env,
571
        tx_env=tx_env,
572
        caller=SYSTEM_ADDRESS,
573
        target=target_address,
574
        gas=SYSTEM_TRANSACTION_GAS,
575
        value=U256(0),
576
        data=data,
577
        code=system_contract_code,
578
        depth=Uint(0),
579
        current_target=target_address,
580
        code_address=target_address,
581
        should_transfer_value=False,
582
        is_static=False,
583
        accessed_addresses=set(),
584
        accessed_storage_keys=set(),
585
        parent_evm=None,
586
    )
587
588
    system_tx_output = process_message_call(system_tx_message)
589
590
    return system_tx_output

process_unchecked_system_transaction

Process a system transaction without checking if the contract contains code or if the transaction fails.

Parameters

block_env : The block scoped environment. target_address : Address of the contract to call. data : Data to pass to the contract.

Returns

system_tx_output : MessageCallOutput Output of processing the system transaction.

def process_unchecked_system_transaction(block_env: ethereum.cancun.vm.BlockEnvironment, ​​target_address: Address, ​​data: Bytes) -> MessageCallOutput:
598
    """
599
    Process a system transaction without checking if the contract contains code
600
    or if the transaction fails.
601
602
    Parameters
603
    ----------
604
    block_env :
605
        The block scoped environment.
606
    target_address :
607
        Address of the contract to call.
608
    data :
609
        Data to pass to the contract.
610
611
    Returns
612
    -------
613
    system_tx_output : `MessageCallOutput`
614
        Output of processing the system transaction.
615
    """
616
    system_contract_code = get_account(block_env.state, target_address).code
617
    return process_system_transaction(
618
        block_env,
619
        target_address,
620
        system_contract_code,
621
        data,
622
    )

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

block_env : The block scoped environment. block_output : The block output for the current block. transactions : Transactions included in the block. withdrawals : Withdrawals to be processed in the current block.

Returns

block_output : The block output for the current block.

def apply_body(block_env: ethereum.shanghai.vm.BlockEnvironmentethereum.cancun.vm.BlockEnvironment, ​​transactions: Tuple[LegacyTransaction | Bytes, ...], ​​withdrawals: Tuple[Withdrawal, ...]) -> ethereum.shanghai.vm.BlockOutputethereum.cancun.vm.BlockOutput:
630
    """
631
    Executes a block.
632
633
    Many of the contents of a block are stored in data structures called
634
    tries. There is a transactions trie which is similar to a ledger of the
635
    transactions stored in the current block. There is also a receipts trie
636
    which stores the results of executing a transaction, like the post state
637
    and gas used. This function creates and executes the block that is to be
638
    added to the chain.
639
640
    Parameters
641
    ----------
642
    block_env :
643
        The block scoped environment.
466
    block_output :
467
        The block output for the current block.
644
    transactions :
645
        Transactions included in the block.
646
    withdrawals :
647
        Withdrawals to be processed in the current block.
648
649
    Returns
650
    -------
651
    block_output :
652
        The block output for the current block.
653
    """
654
    block_output = vm.BlockOutput()
655
656
    process_unchecked_system_transaction(
657
        block_env=block_env,
658
        target_address=BEACON_ROOTS_ADDRESS,
659
        data=block_env.parent_beacon_block_root,
660
    )
661
662
    for i, tx in enumerate(map(decode_transaction, transactions)):
663
        process_transaction(block_env, block_output, tx, Uint(i))
664
665
    process_withdrawals(block_env, block_output, withdrawals)
666
667
    return block_output

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

block_env : Environment for the Ethereum Virtual Machine. block_output : The block output for the current block. tx : Transaction to execute. index: Index of the transaction in the block.

def process_transaction(block_env: ethereum.shanghai.vm.BlockEnvironmentethereum.cancun.vm.BlockEnvironment, ​​block_output: ethereum.shanghai.vm.BlockOutputethereum.cancun.vm.BlockOutput, ​​tx: Transaction, ​​index: Uint) -> None:
676
    """
677
    Execute a transaction against the provided environment.
678
679
    This function processes the actions needed to execute a transaction.
680
    It decrements the sender's account after calculating the gas fee and
681
    refunds them the proper amount after execution. Calling contracts,
682
    deploying code, and incrementing nonces are all examples of actions that
683
    happen within this function or from a call made within this function.
684
685
    Accounts that are marked for deletion are processed and destroyed after
686
    execution.
687
688
    Parameters
689
    ----------
690
    block_env :
691
        Environment for the Ethereum Virtual Machine.
692
    block_output :
693
        The block output for the current block.
694
    tx :
695
        Transaction to execute.
696
    index:
697
        Index of the transaction in the block.
698
    """
699
    trie_set(
700
        block_output.transactions_trie,
701
        rlp.encode(index),
702
        encode_transaction(tx),
703
    )
704
705
    intrinsic_gas = validate_transaction(tx)
706
707
    (
708
        sender,
527
        effective_gas_price,
709
        effective_gas_price,
710
        blob_versioned_hashes,
711
        tx_blob_gas_used,
712
    ) = check_transaction(
713
        block_env=block_env,
714
        block_output=block_output,
715
        tx=tx,
716
    )
717
718
    sender_account = get_account(block_env.state, sender)
719
720
    if isinstance(tx, BlobTransaction):
721
        blob_gas_fee = calculate_data_fee(block_env.excess_blob_gas, tx)
722
    else:
723
        blob_gas_fee = Uint(0)
724
725
    effective_gas_fee = tx.gas * effective_gas_price
726
727
    gas = tx.gas - intrinsic_gas
728
    increment_nonce(block_env.state, sender)
729
730
    sender_balance_after_gas_fee = (
542
        Uint(sender_account.balance) - effective_gas_fee
731
        Uint(sender_account.balance) - effective_gas_fee - blob_gas_fee
732
    )
733
    set_account_balance(
734
        block_env.state, sender, U256(sender_balance_after_gas_fee)
735
    )
736
737
    access_list_addresses = set()
738
    access_list_storage_keys = set()
739
    access_list_addresses.add(block_env.coinbase)
551
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
740
    if isinstance(
741
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
742
    ):
743
        for access in tx.access_list:
744
            access_list_addresses.add(access.account)
745
            for slot in access.slots:
746
                access_list_storage_keys.add((access.account, slot))
747
748
    tx_env = vm.TransactionEnvironment(
749
        origin=sender,
750
        gas_price=effective_gas_price,
751
        gas=gas,
752
        access_list_addresses=access_list_addresses,
753
        access_list_storage_keys=access_list_storage_keys,
754
        transient_storage=TransientStorage(),
755
        blob_versioned_hashes=blob_versioned_hashes,
756
        index_in_block=index,
757
        tx_hash=get_transaction_hash(encode_transaction(tx)),
758
        traces=[],
759
    )
760
761
    message = prepare_message(block_env, tx_env, tx)
762
763
    tx_output = process_message_call(message)
764
765
    tx_gas_used_before_refund = tx.gas - tx_output.gas_left
766
    tx_gas_refund = min(
767
        tx_gas_used_before_refund // Uint(5), Uint(tx_output.refund_counter)
768
    )
769
    tx_gas_used_after_refund = tx_gas_used_before_refund - tx_gas_refund
770
    tx_gas_left = tx.gas - tx_gas_used_after_refund
771
    gas_refund_amount = tx_gas_left * effective_gas_price
772
773
    # For non-1559 transactions effective_gas_price == tx.gas_price
774
    priority_fee_per_gas = effective_gas_price - block_env.base_fee_per_gas
775
    transaction_fee = tx_gas_used_after_refund * priority_fee_per_gas
776
777
    # refund gas
778
    sender_balance_after_refund = get_account(
779
        block_env.state, sender
780
    ).balance + U256(gas_refund_amount)
781
    set_account_balance(block_env.state, sender, sender_balance_after_refund)
782
783
    # transfer miner fees
784
    coinbase_balance_after_mining_fee = get_account(
785
        block_env.state, block_env.coinbase
786
    ).balance + U256(transaction_fee)
787
    if coinbase_balance_after_mining_fee != 0:
788
        set_account_balance(
789
            block_env.state,
790
            block_env.coinbase,
791
            coinbase_balance_after_mining_fee,
792
        )
793
    elif account_exists_and_is_empty(block_env.state, block_env.coinbase):
794
        destroy_account(block_env.state, block_env.coinbase)
795
796
    for address in tx_output.accounts_to_delete:
797
        destroy_account(block_env.state, address)
798
799
    block_output.block_gas_used += tx_gas_used_after_refund
800
    block_output.blob_gas_used += tx_blob_gas_used
801
802
    receipt = make_receipt(
803
        tx, tx_output.error, block_output.block_gas_used, tx_output.logs
804
    )
805
806
    receipt_key = rlp.encode(Uint(index))
807
    block_output.receipt_keys += (receipt_key,)
808
809
    trie_set(
810
        block_output.receipts_trie,
811
        receipt_key,
812
        receipt,
813
    )
814
815
    block_output.block_logs += tx_output.logs

process_withdrawals

Increase the balance of the withdrawing account.

def process_withdrawals(block_env: ethereum.shanghai.vm.BlockEnvironmentethereum.cancun.vm.BlockEnvironment, ​​block_output: ethereum.shanghai.vm.BlockOutputethereum.cancun.vm.BlockOutput, ​​withdrawals: Tuple[Withdrawal, ...]) -> None:
823
    """
824
    Increase the balance of the withdrawing account.
825
    """
826
827
    def increase_recipient_balance(recipient: Account) -> None:
828
        recipient.balance += wd.amount * U256(10**9)
829
830
    for i, wd in enumerate(withdrawals):
831
        trie_set(
832
            block_output.withdrawals_trie,
833
            rlp.encode(Uint(i)),
834
            rlp.encode(wd),
835
        )
836
837
        modify_state(block_env.state, wd.address, increase_recipient_balance)
838
839
        if account_exists_and_is_empty(block_env.state, wd.address):
840
            destroy_account(block_env.state, wd.address)

check_gas_limit

Validates the gas limit for a block.

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

Parameters

gas_limit : Gas limit to validate.

parent_gas_limit : Gas limit of the parent block.

Returns

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

def check_gas_limit(gas_limit: Uint, ​​parent_gas_limit: Uint) -> bool:
844
    """
845
    Validates the gas limit for a block.
846
847
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
848
    quotient of the parent block's gas limit and the
849
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
850
    passed through as a parameter is greater than or equal to the *sum* of
851
    the parent's gas and the adjustment delta then the limit for gas is too
852
    high and fails this function's check. Similarly, if the limit is less
853
    than or equal to the *difference* of the parent's gas and the adjustment
854
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
855
    check fails because the gas limit doesn't allow for a sufficient or
856
    reasonable amount of gas to be used on a block.
857
858
    Parameters
859
    ----------
860
    gas_limit :
861
        Gas limit to validate.
862
863
    parent_gas_limit :
864
        Gas limit of the parent block.
865
866
    Returns
867
    -------
868
    check : `bool`
869
        True if gas limit constraints are satisfied, False otherwise.
870
    """
871
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
872
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
873
        return False
874
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
875
        return False
876
    if gas_limit < GAS_LIMIT_MINIMUM:
877
        return False
878
879
    return True