ethereum.forks.shanghai.forkethereum.forks.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
    """
125
    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]:
129
    """
130
    Obtain the list of hashes of the previous 256 blocks in order of
131
    increasing block number.
132
133
    This function will return less hashes for the first 256 blocks.
134
135
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
136
    therefore this function retrieves them.
137
138
    Parameters
139
    ----------
140
    chain :
141
        History and current state.
142
143
    Returns
144
    -------
145
    recent_block_hashes : `List[Hash32]`
146
        Hashes of the recent 256 blocks in order of increasing block number.
147
148
    """
149
    recent_blocks = chain.blocks[-255:]
150
    # TODO: This function has not been tested rigorously
151
    if len(recent_blocks) == 0:
152
        return []
153
154
    recent_block_hashes = []
155
156
    for block in recent_blocks:
157
        prev_block_hash = block.header.parent_hash
158
        recent_block_hashes.append(prev_block_hash)
159
160
    # We are computing the hash only for the most recent block and not for
161
    # the rest of the blocks as they have successors which have the hash of
162
    # the current block as parent hash.
163
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
164
    recent_block_hashes.append(most_recent_block_hash)
165
166
    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:
170
    """
171
    Attempts to apply a block to an existing block chain.
172
173
    All parts of the block's contents need to be verified before being added
174
    to the chain. Blocks are verified by ensuring that the contents of the
175
    block make logical sense with the contents of the parent block. The
176
    information in the block's header must also match the corresponding
177
    information in the block.
178
179
    To implement Ethereum, in theory clients are only required to store the
180
    most recent 255 blocks of the chain since as far as execution is
181
    concerned, only those blocks are accessed. Practically, however, clients
182
    should store more blocks to handle reorgs.
183
184
    Parameters
185
    ----------
186
    chain :
187
        History and current state.
188
    block :
189
        Block to apply to `chain`.
190
191
    """
192
    validate_header(chain, block.header)
193
    if block.ommers != ():
194
        raise InvalidBlock
195
196
    block_env = vm.BlockEnvironment(
197
        chain_id=chain.chain_id,
198
        state=chain.state,
199
        block_gas_limit=block.header.gas_limit,
200
        block_hashes=get_last_256_block_hashes(chain),
201
        coinbase=block.header.coinbase,
202
        number=block.header.number,
203
        base_fee_per_gas=block.header.base_fee_per_gas,
204
        time=block.header.timestamp,
205
        prev_randao=block.header.prev_randao,
206
        excess_blob_gas=block.header.excess_blob_gas,
207
        parent_beacon_block_root=block.header.parent_beacon_block_root,
208
    )
209
210
    block_output = apply_body(
211
        block_env=block_env,
212
        transactions=block.transactions,
213
        withdrawals=block.withdrawals,
214
    )
215
    block_state_root = state_root(block_env.state)
216
    transactions_root = root(block_output.transactions_trie)
217
    receipt_root = root(block_output.receipts_trie)
218
    block_logs_bloom = logs_bloom(block_output.block_logs)
219
    withdrawals_root = root(block_output.withdrawals_trie)
220
221
    if block_output.block_gas_used != block.header.gas_used:
222
        raise InvalidBlock(
223
            f"{block_output.block_gas_used} != {block.header.gas_used}"
224
        )
225
    if transactions_root != block.header.transactions_root:
226
        raise InvalidBlock
227
    if block_state_root != block.header.state_root:
228
        raise InvalidBlock
229
    if receipt_root != block.header.receipt_root:
230
        raise InvalidBlock
231
    if block_logs_bloom != block.header.bloom:
232
        raise InvalidBlock
233
    if withdrawals_root != block.header.withdrawals_root:
234
        raise InvalidBlock
235
    if block_output.blob_gas_used != block.header.blob_gas_used:
236
        raise InvalidBlock
237
238
    chain.blocks.append(block)
239
    if len(chain.blocks) > 255:
240
        # Real clients have to store more blocks to deal with reorgs, but the
241
        # protocol only requires the last 255
242
        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:
251
    """
252
    Calculates the base fee per gas for the block.
253
254
    Parameters
255
    ----------
256
    block_gas_limit :
257
        Gas limit of the block for which the base fee is being calculated.
258
    parent_gas_limit :
259
        Gas limit of the parent block.
260
    parent_gas_used :
261
        Gas used in the parent block.
262
    parent_base_fee_per_gas :
263
        Base fee per gas of the parent block.
264
265
    Returns
266
    -------
267
    base_fee_per_gas : `Uint`
268
        Base fee per gas for the block.
269
270
    """
271
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
272
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
273
        raise InvalidBlock
274
275
    if parent_gas_used == parent_gas_target:
276
        expected_base_fee_per_gas = parent_base_fee_per_gas
277
    elif parent_gas_used > parent_gas_target:
278
        gas_used_delta = parent_gas_used - parent_gas_target
279
280
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
281
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
282
283
        base_fee_per_gas_delta = max(
284
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
285
            Uint(1),
286
        )
287
288
        expected_base_fee_per_gas = (
289
            parent_base_fee_per_gas + base_fee_per_gas_delta
290
        )
291
    else:
292
        gas_used_delta = parent_gas_target - parent_gas_used
293
294
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
295
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
296
297
        base_fee_per_gas_delta = (
298
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
299
        )
300
301
        expected_base_fee_per_gas = (
302
            parent_base_fee_per_gas - base_fee_per_gas_delta
303
        )
304
305
    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:
309
    """
310
    Verifies a block header.
311
312
    In order to consider a block's header valid, the logic for the
313
    quantities in the header should match the logic for the block itself.
314
    For example the header timestamp should be greater than the block's parent
315
    timestamp because the block was created *after* the parent block.
316
    Additionally, the block's number should be directly following the parent
317
    block's number since it is the next block in the sequence.
318
319
    Parameters
320
    ----------
321
    chain :
322
        History and current state.
323
    header :
324
        Header to check for correctness.
325
326
    """
327
    if header.number < Uint(1):
328
        raise InvalidBlock
329
330
    parent_header = chain.blocks[-1].header
331
332
    excess_blob_gas = calculate_excess_blob_gas(parent_header)
333
    if header.excess_blob_gas != excess_blob_gas:
334
        raise InvalidBlock
335
336
    if header.gas_used > header.gas_limit:
337
        raise InvalidBlock
338
339
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
340
        header.gas_limit,
341
        parent_header.gas_limit,
342
        parent_header.gas_used,
343
        parent_header.base_fee_per_gas,
344
    )
345
    if expected_base_fee_per_gas != header.base_fee_per_gas:
346
        raise InvalidBlock
347
    if header.timestamp <= parent_header.timestamp:
348
        raise InvalidBlock
349
    if header.number != parent_header.number + Uint(1):
350
        raise InvalidBlock
351
    if len(header.extra_data) > 32:
352
        raise InvalidBlock
353
    if header.difficulty != 0:
354
        raise InvalidBlock
355
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
356
        raise InvalidBlock
357
    if header.ommers_hash != EMPTY_OMMER_HASH:
358
        raise InvalidBlock
359
360
    block_parent_hash = keccak256(rlp.encode(parent_header))
361
    if header.parent_hash != block_parent_hash:
362
        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.forks.shanghai.vm.BlockEnvironmentethereum.forks.cancun.vm.BlockEnvironment, ​​block_output: ethereum.forks.shanghai.vm.BlockOutputethereum.forks.cancun.vm.BlockOutput, ​​tx: Transaction) -> Tuple[Address, Uint, Tuple[VersionedHash, ...]U64]:
370
    """
371
    Check if the transaction is includable in the block.
372
373
    Parameters
374
    ----------
375
    block_env :
376
        The block scoped environment.
377
    block_output :
378
        The block output for the current block.
379
    tx :
380
        The transaction.
381
382
    Returns
383
    -------
384
    sender_address :
385
        The sender of the transaction.
386
    effective_gas_price :
387
        The price to charge for gas when the transaction is executed.
388
    blob_versioned_hashes :
389
        The blob versioned hashes of the transaction.
390
    tx_blob_gas_used:
391
        The blob gas used by the transaction.
392
393
    Raises
394
    ------
395
    InvalidBlock :
396
        If the transaction is not includable.
397
    GasUsedExceedsLimitError :
398
        If the gas used by the transaction exceeds the block's gas limit.
399
    NonceMismatchError :
400
        If the nonce of the transaction is not equal to the sender's nonce.
401
    InsufficientBalanceError :
402
        If the sender's balance is not enough to pay for the transaction.
403
    InvalidSenderError :
404
        If the transaction is from an address that does not exist anymore.
405
    PriorityFeeGreaterThanMaxFeeError :
406
        If the priority fee is greater than the maximum fee per gas.
407
    InsufficientMaxFeePerGasError :
408
        If the maximum fee per gas is insufficient for the transaction.
409
    InsufficientMaxFeePerBlobGasError :
410
        If the maximum fee per blob gas is insufficient for the transaction.
411
    BlobGasLimitExceededError :
412
        If the blob gas used by the transaction exceeds the block's blob gas
413
        limit.
414
    InvalidBlobVersionedHashError :
415
        If the transaction contains a blob versioned hash with an invalid
416
        version.
417
    NoBlobDataError :
418
        If the transaction is a type 3 but has no blobs.
419
    TransactionTypeContractCreationError:
420
        If the transaction type is not allowed to create contracts.
421
422
    """
423
    gas_available = block_env.block_gas_limit - block_output.block_gas_used
424
    blob_gas_available = MAX_BLOB_GAS_PER_BLOCK - block_output.blob_gas_used
425
426
    if tx.gas > gas_available:
427
        raise GasUsedExceedsLimitError("gas used exceeds limit")
428
429
    tx_blob_gas_used = calculate_total_blob_gas(tx)
430
    if tx_blob_gas_used > blob_gas_available:
431
        raise BlobGasLimitExceededError("blob gas limit exceeded")
432
433
    sender_address = recover_sender(block_env.chain_id, tx)
434
    sender_account = get_account(block_env.state, sender_address)
435
381
    if isinstance(tx, FeeMarketTransaction):
436
    if isinstance(tx, (FeeMarketTransaction, BlobTransaction)):
437
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
438
            raise PriorityFeeGreaterThanMaxFeeError(
439
                "priority fee greater than max fee"
440
            )
441
        if tx.max_fee_per_gas < block_env.base_fee_per_gas:
442
            raise InsufficientMaxFeePerGasError(
443
                tx.max_fee_per_gas, block_env.base_fee_per_gas
444
            )
445
446
        priority_fee_per_gas = min(
447
            tx.max_priority_fee_per_gas,
448
            tx.max_fee_per_gas - block_env.base_fee_per_gas,
449
        )
450
        effective_gas_price = priority_fee_per_gas + block_env.base_fee_per_gas
451
        max_gas_fee = tx.gas * tx.max_fee_per_gas
452
    else:
453
        if tx.gas_price < block_env.base_fee_per_gas:
454
            raise InvalidBlock
455
        effective_gas_price = tx.gas_price
456
        max_gas_fee = tx.gas * tx.gas_price
457
458
    if isinstance(tx, BlobTransaction):
459
        if not isinstance(tx.to, Address):
460
            raise TransactionTypeContractCreationError(tx)
461
        if len(tx.blob_versioned_hashes) == 0:
462
            raise NoBlobDataError("no blob data in transaction")
463
        for blob_versioned_hash in tx.blob_versioned_hashes:
464
            if blob_versioned_hash[0:1] != VERSIONED_HASH_VERSION_KZG:
465
                raise InvalidBlobVersionedHashError(
466
                    "invalid blob versioned hash"
467
                )
468
469
        blob_gas_price = calculate_blob_gas_price(block_env.excess_blob_gas)
470
        if Uint(tx.max_fee_per_blob_gas) < blob_gas_price:
471
            raise InsufficientMaxFeePerBlobGasError(
472
                "insufficient max fee per blob gas"
473
            )
474
475
        max_gas_fee += Uint(calculate_total_blob_gas(tx)) * Uint(
476
            tx.max_fee_per_blob_gas
477
        )
478
        blob_versioned_hashes = tx.blob_versioned_hashes
479
    else:
480
        blob_versioned_hashes = ()
481
    if sender_account.nonce > Uint(tx.nonce):
482
        raise NonceMismatchError("nonce too low")
483
    elif sender_account.nonce < Uint(tx.nonce):
484
        raise NonceMismatchError("nonce too high")
485
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
486
        raise InsufficientBalanceError("insufficient sender balance")
487
    if sender_account.code_hash != EMPTY_CODE_HASH:
488
        raise InvalidSenderError("not EOA")
489
412
    return sender_address, effective_gas_price
490
    return (
491
        sender_address,
492
        effective_gas_price,
493
        blob_versioned_hashes,
494
        tx_blob_gas_used,
495
    )

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:
504
    """
505
    Make the receipt for a transaction that was executed.
506
507
    Parameters
508
    ----------
509
    tx :
510
        The executed transaction.
511
    error :
512
        Error in the top level frame of the transaction, if any.
513
    cumulative_gas_used :
514
        The total gas used so far in the block after the transaction was
515
        executed.
516
    logs :
517
        The logs produced by the transaction.
518
519
    Returns
520
    -------
521
    receipt :
522
        The receipt for the transaction.
523
524
    """
525
    receipt = Receipt(
526
        succeeded=error is None,
527
        cumulative_gas_used=cumulative_gas_used,
528
        bloom=logs_bloom(logs),
529
        logs=logs,
530
    )
531
532
    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.forks.cancun.vm.BlockEnvironment, ​​target_address: Address, ​​system_contract_code: Bytes, ​​data: Bytes) -> MessageCallOutput:
541
    """
542
    Process a system transaction with the given code.
543
544
    Prefer calling `process_unchecked_system_transaction` unless the contract
545
    code has already been read from the state.
546
547
    Parameters
548
    ----------
549
    block_env :
550
        The block scoped environment.
551
    target_address :
552
        Address of the contract to call.
553
    system_contract_code :
554
        Code of the contract to call.
555
    data :
556
        Data to pass to the contract.
557
558
    Returns
559
    -------
560
    system_tx_output : `MessageCallOutput`
561
        Output of processing the system transaction.
562
563
    """
564
    tx_env = vm.TransactionEnvironment(
565
        origin=SYSTEM_ADDRESS,
566
        gas_price=block_env.base_fee_per_gas,
567
        gas=SYSTEM_TRANSACTION_GAS,
568
        access_list_addresses=set(),
569
        access_list_storage_keys=set(),
570
        transient_storage=TransientStorage(),
571
        blob_versioned_hashes=(),
572
        index_in_block=None,
573
        tx_hash=None,
574
    )
575
576
    system_tx_message = Message(
577
        block_env=block_env,
578
        tx_env=tx_env,
579
        caller=SYSTEM_ADDRESS,
580
        target=target_address,
581
        gas=SYSTEM_TRANSACTION_GAS,
582
        value=U256(0),
583
        data=data,
584
        code=system_contract_code,
585
        depth=Uint(0),
586
        current_target=target_address,
587
        code_address=target_address,
588
        should_transfer_value=False,
589
        is_static=False,
590
        accessed_addresses=set(),
591
        accessed_storage_keys=set(),
592
        parent_evm=None,
593
    )
594
595
    system_tx_output = process_message_call(system_tx_message)
596
597
    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.forks.cancun.vm.BlockEnvironment, ​​target_address: Address, ​​data: Bytes) -> MessageCallOutput:
605
    """
606
    Process a system transaction without checking if the contract contains code
607
    or if the transaction fails.
608
609
    Parameters
610
    ----------
611
    block_env :
612
        The block scoped environment.
613
    target_address :
614
        Address of the contract to call.
615
    data :
616
        Data to pass to the contract.
617
618
    Returns
619
    -------
620
    system_tx_output : `MessageCallOutput`
621
        Output of processing the system transaction.
622
623
    """
624
    system_contract_code = get_code(
625
        block_env.state,
626
        get_account(block_env.state, target_address).code_hash,
627
    )
628
    return process_system_transaction(
629
        block_env,
630
        target_address,
631
        system_contract_code,
632
        data,
633
    )

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.forks.shanghai.vm.BlockEnvironmentethereum.forks.cancun.vm.BlockEnvironment, ​​transactions: Tuple[LegacyTransaction | Bytes, ...], ​​withdrawals: Tuple[Withdrawal, ...]) -> ethereum.forks.shanghai.vm.BlockOutputethereum.forks.cancun.vm.BlockOutput:
641
    """
642
    Executes a block.
643
644
    Many of the contents of a block are stored in data structures called
645
    tries. There is a transactions trie which is similar to a ledger of the
646
    transactions stored in the current block. There is also a receipts trie
647
    which stores the results of executing a transaction, like the post state
648
    and gas used. This function creates and executes the block that is to be
649
    added to the chain.
650
651
    Parameters
652
    ----------
653
    block_env :
654
        The block scoped environment.
471
    block_output :
472
        The block output for the current block.
655
    transactions :
656
        Transactions included in the block.
657
    withdrawals :
658
        Withdrawals to be processed in the current block.
659
660
    Returns
661
    -------
662
    block_output :
663
        The block output for the current block.
664
665
    """
666
    block_output = vm.BlockOutput()
667
668
    process_unchecked_system_transaction(
669
        block_env=block_env,
670
        target_address=BEACON_ROOTS_ADDRESS,
671
        data=block_env.parent_beacon_block_root,
672
    )
673
674
    for i, tx in enumerate(map(decode_transaction, transactions)):
675
        process_transaction(block_env, block_output, tx, Uint(i))
676
677
    process_withdrawals(block_env, block_output, withdrawals)
678
679
    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 balance 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.forks.shanghai.vm.BlockEnvironmentethereum.forks.cancun.vm.BlockEnvironment, ​​block_output: ethereum.forks.shanghai.vm.BlockOutputethereum.forks.cancun.vm.BlockOutput, ​​tx: Transaction, ​​index: Uint) -> None:
688
    """
689
    Execute a transaction against the provided environment.
690
691
    This function processes the actions needed to execute a transaction.
692
    It decrements the sender's account balance after calculating the gas fee
693
    and refunds them the proper amount after execution. Calling contracts,
694
    deploying code, and incrementing nonces are all examples of actions that
695
    happen within this function or from a call made within this function.
696
697
    Accounts that are marked for deletion are processed and destroyed after
698
    execution.
699
700
    Parameters
701
    ----------
702
    block_env :
703
        Environment for the Ethereum Virtual Machine.
704
    block_output :
705
        The block output for the current block.
706
    tx :
707
        Transaction to execute.
708
    index:
709
        Index of the transaction in the block.
710
711
    """
712
    trie_set(
713
        block_output.transactions_trie,
714
        rlp.encode(index),
715
        encode_transaction(tx),
716
    )
717
718
    intrinsic_gas = validate_transaction(tx)
719
720
    (
721
        sender,
534
        effective_gas_price,
722
        effective_gas_price,
723
        blob_versioned_hashes,
724
        tx_blob_gas_used,
725
    ) = check_transaction(
726
        block_env=block_env,
727
        block_output=block_output,
728
        tx=tx,
729
    )
730
731
    sender_account = get_account(block_env.state, sender)
732
733
    if isinstance(tx, BlobTransaction):
734
        blob_gas_fee = calculate_data_fee(block_env.excess_blob_gas, tx)
735
    else:
736
        blob_gas_fee = Uint(0)
737
738
    effective_gas_fee = tx.gas * effective_gas_price
739
740
    gas = tx.gas - intrinsic_gas
741
    increment_nonce(block_env.state, sender)
742
743
    sender_balance_after_gas_fee = (
549
        Uint(sender_account.balance) - effective_gas_fee
744
        Uint(sender_account.balance) - effective_gas_fee - blob_gas_fee
745
    )
746
    set_account_balance(
747
        block_env.state, sender, U256(sender_balance_after_gas_fee)
748
    )
749
750
    access_list_addresses = set()
751
    access_list_storage_keys = set()
752
    access_list_addresses.add(block_env.coinbase)
558
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
753
    if isinstance(
754
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
755
    ):
756
        for access in tx.access_list:
757
            access_list_addresses.add(access.account)
758
            for slot in access.slots:
759
                access_list_storage_keys.add((access.account, slot))
760
761
    tx_env = vm.TransactionEnvironment(
762
        origin=sender,
763
        gas_price=effective_gas_price,
764
        gas=gas,
765
        access_list_addresses=access_list_addresses,
766
        access_list_storage_keys=access_list_storage_keys,
767
        transient_storage=TransientStorage(),
768
        blob_versioned_hashes=blob_versioned_hashes,
769
        index_in_block=index,
770
        tx_hash=get_transaction_hash(encode_transaction(tx)),
771
    )
772
773
    message = prepare_message(block_env, tx_env, tx)
774
775
    tx_output = process_message_call(message)
776
777
    tx_gas_used_before_refund = tx.gas - tx_output.gas_left
778
    tx_gas_refund = min(
779
        tx_gas_used_before_refund // Uint(5), Uint(tx_output.refund_counter)
780
    )
781
    tx_gas_used_after_refund = tx_gas_used_before_refund - tx_gas_refund
782
    tx_gas_left = tx.gas - tx_gas_used_after_refund
783
    gas_refund_amount = tx_gas_left * effective_gas_price
784
785
    # For non-1559 transactions effective_gas_price == tx.gas_price
786
    priority_fee_per_gas = effective_gas_price - block_env.base_fee_per_gas
787
    transaction_fee = tx_gas_used_after_refund * priority_fee_per_gas
788
789
    # refund gas
790
    sender_balance_after_refund = get_account(
791
        block_env.state, sender
792
    ).balance + U256(gas_refund_amount)
793
    set_account_balance(block_env.state, sender, sender_balance_after_refund)
794
795
    # transfer miner fees
796
    coinbase_balance_after_mining_fee = get_account(
797
        block_env.state, block_env.coinbase
798
    ).balance + U256(transaction_fee)
799
    set_account_balance(
800
        block_env.state,
801
        block_env.coinbase,
802
        coinbase_balance_after_mining_fee,
803
    )
804
805
    for address in tx_output.accounts_to_delete:
806
        destroy_account(block_env.state, address)
807
808
    block_output.block_gas_used += tx_gas_used_after_refund
809
    block_output.blob_gas_used += tx_blob_gas_used
810
811
    receipt = make_receipt(
812
        tx, tx_output.error, block_output.block_gas_used, tx_output.logs
813
    )
814
815
    receipt_key = rlp.encode(Uint(index))
816
    block_output.receipt_keys += (receipt_key,)
817
818
    trie_set(
819
        block_output.receipts_trie,
820
        receipt_key,
821
        receipt,
822
    )
823
824
    block_output.block_logs += tx_output.logs

process_withdrawals

Increase the balance of the withdrawing account.

def process_withdrawals(block_env: ethereum.forks.shanghai.vm.BlockEnvironmentethereum.forks.cancun.vm.BlockEnvironment, ​​block_output: ethereum.forks.shanghai.vm.BlockOutputethereum.forks.cancun.vm.BlockOutput, ​​withdrawals: Tuple[Withdrawal, ...]) -> None:
832
    """
833
    Increase the balance of the withdrawing account.
834
    """
835
836
    def increase_recipient_balance(recipient: Account) -> None:
837
        recipient.balance += wd.amount * U256(10**9)
838
839
    for i, wd in enumerate(withdrawals):
840
        trie_set(
841
            block_output.withdrawals_trie,
842
            rlp.encode(Uint(i)),
843
            rlp.encode(wd),
844
        )
845
846
        modify_state(block_env.state, wd.address, increase_recipient_balance)

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