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

85
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

86
ELASTICITY_MULTIPLIER = Uint(2)

EMPTY_OMMER_HASH

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

SYSTEM_ADDRESS

88
SYSTEM_ADDRESS = hex_to_address("0xfffffffffffffffffffffffffffffffffffffffe")

BEACON_ROOTS_ADDRESS

89
BEACON_ROOTS_ADDRESS = hex_to_address(
90
    "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"
91
)

SYSTEM_TRANSACTION_GAS

92
SYSTEM_TRANSACTION_GAS = Uint(30000000)

MAX_BLOB_GAS_PER_BLOCK

93
MAX_BLOB_GAS_PER_BLOCK: Final[U64] = U64(786432)

VERSIONED_HASH_VERSION_KZG

94
VERSIONED_HASH_VERSION_KZG = b"\x01"

BlockChain

History and current state of the block chain.

97
@final
98
@dataclass
class BlockChain:

blocks

104
    blocks: List[Block]

state

105
    state: State

chain_id

106
    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:
110
    <snip>
129
    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]:
133
    <snip>
153
    recent_blocks = chain.blocks[-255:]
154
    if len(recent_blocks) == 0:
155
        return []
156
157
    recent_block_hashes = []
158
159
    for block in recent_blocks:
160
        prev_block_hash = block.header.parent_hash
161
        recent_block_hashes.append(prev_block_hash)
162
163
    # We are computing the hash only for the most recent block and not for
164
    # the rest of the blocks as they have successors which have the hash of
165
    # the current block as parent hash.
166
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
167
    recent_block_hashes.append(most_recent_block_hash)
168
169
    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:
173
    <snip>
195
    validate_header(chain, block.header)
196
    if block.ommers != ():
197
        raise InvalidBlock
198
199
    block_state = BlockState(pre_state=chain.state)
200
201
    block_env = vm.BlockEnvironment(
202
        chain_id=chain.chain_id,
203
        state=block_state,
204
        block_gas_limit=block.header.gas_limit,
205
        block_hashes=get_last_256_block_hashes(chain),
206
        coinbase=block.header.coinbase,
207
        number=block.header.number,
208
        base_fee_per_gas=block.header.base_fee_per_gas,
209
        time=block.header.timestamp,
210
        prev_randao=block.header.prev_randao,
211
        excess_blob_gas=block.header.excess_blob_gas,
212
        parent_beacon_block_root=block.header.parent_beacon_block_root,
213
    )
214
215
    block_output = apply_body(
216
        block_env=block_env,
217
        transactions=block.transactions,
218
        withdrawals=block.withdrawals,
219
    )
220
    block_diff = extract_block_diff(block_state)
221
    block_state_root = chain.state.compute_state_root(block_diff)
222
    transactions_root = root(block_output.transactions_trie)
223
    receipt_root = root(block_output.receipts_trie)
224
    block_logs_bloom = logs_bloom(block_output.block_logs)
225
    withdrawals_root = root(block_output.withdrawals_trie)
226
227
    if block_output.block_gas_used != block.header.gas_used:
228
        raise InvalidBlock(
229
            f"{block_output.block_gas_used} != {block.header.gas_used}"
230
        )
231
    if transactions_root != block.header.transactions_root:
232
        raise InvalidBlock
233
    if block_state_root != block.header.state_root:
234
        raise InvalidBlock
235
    if receipt_root != block.header.receipt_root:
236
        raise InvalidBlock
237
    if block_logs_bloom != block.header.bloom:
238
        raise InvalidBlock
239
    if withdrawals_root != block.header.withdrawals_root:
240
        raise InvalidBlock
241
    if block_output.blob_gas_used != block.header.blob_gas_used:
242
        raise InvalidBlock
243
244
    apply_changes_to_state(chain.state, block_diff)
245
    chain.blocks.append(block)
246
    if len(chain.blocks) > 255:
247
        # Real clients have to store more blocks to deal with reorgs, but the
248
        # protocol only requires the last 255
249
        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:
258
    <snip>
278
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
279
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
280
        raise InvalidBlock
281
282
    if parent_gas_used == parent_gas_target:
283
        expected_base_fee_per_gas = parent_base_fee_per_gas
284
    elif parent_gas_used > parent_gas_target:
285
        gas_used_delta = parent_gas_used - parent_gas_target
286
287
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
288
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
289
290
        base_fee_per_gas_delta = max(
291
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
292
            Uint(1),
293
        )
294
295
        expected_base_fee_per_gas = (
296
            parent_base_fee_per_gas + base_fee_per_gas_delta
297
        )
298
    else:
299
        gas_used_delta = parent_gas_target - parent_gas_used
300
301
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
302
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
303
304
        base_fee_per_gas_delta = (
305
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
306
        )
307
308
        expected_base_fee_per_gas = (
309
            parent_base_fee_per_gas - base_fee_per_gas_delta
310
        )
311
312
    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:
316
    <snip>
334
    if header.number < Uint(1):
335
        raise InvalidBlock
336
337
    parent_header = chain.blocks[-1].header
338
339
    excess_blob_gas = calculate_excess_blob_gas(parent_header)
340
    if header.excess_blob_gas != excess_blob_gas:
341
        raise InvalidBlock
342
343
    if header.gas_used > header.gas_limit:
344
        raise InvalidBlock
345
346
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
347
        header.gas_limit,
348
        parent_header.gas_limit,
349
        parent_header.gas_used,
350
        parent_header.base_fee_per_gas,
351
    )
352
    if expected_base_fee_per_gas != header.base_fee_per_gas:
353
        raise InvalidBlock
354
    if header.timestamp <= parent_header.timestamp:
355
        raise InvalidBlock
356
    if header.number != parent_header.number + Uint(1):
357
        raise InvalidBlock
358
    if len(header.extra_data) > 32:
359
        raise InvalidBlock
360
    if header.difficulty != 0:
361
        raise InvalidBlock
362
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
363
        raise InvalidBlock
364
    if header.ommers_hash != EMPTY_OMMER_HASH:
365
        raise InvalidBlock
366
367
    block_parent_hash = keccak256(rlp.encode(parent_header))
368
    if header.parent_hash != block_parent_hash:
369
        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. tx_state : The transaction state tracker.

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. 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, ​​tx_state: TransactionState) -> Tuple[Address, Uint, Tuple[VersionedHash, ...]U64]:
378
    <snip>
431
    gas_available = block_env.block_gas_limit - block_output.block_gas_used
432
    blob_gas_available = MAX_BLOB_GAS_PER_BLOCK - block_output.blob_gas_used
433
434
    if tx.gas > gas_available:
435
        raise GasUsedExceedsLimitError("gas used exceeds limit")
436
437
    tx_blob_gas_used = calculate_total_blob_gas(tx)
438
    if tx_blob_gas_used > blob_gas_available:
439
        raise BlobGasLimitExceededError("blob gas limit exceeded")
440
441
    tx_chain_id = chain_id(tx)
442
    if tx_chain_id is not None and tx_chain_id != block_env.chain_id:
443
        raise WrongChainIdError(
444
            expected=block_env.chain_id,
445
            actual=tx_chain_id,
446
        )
447
448
    sender_address = recover_sender(tx)
449
    sender_account = get_account(tx_state, sender_address)
450
396
    if isinstance(tx, FeeMarketTransaction):
451
    if isinstance(tx, FeeMarketCapableTransaction):
452
        if tx.max_fee_per_gas < block_env.base_fee_per_gas:
453
            raise InsufficientMaxFeePerGasError(
454
                tx.max_fee_per_gas, block_env.base_fee_per_gas
455
            )
456
457
        priority_fee_per_gas = min(
458
            tx.max_priority_fee_per_gas,
459
            tx.max_fee_per_gas - block_env.base_fee_per_gas,
460
        )
461
        effective_gas_price = priority_fee_per_gas + block_env.base_fee_per_gas
462
        max_gas_fee = tx.gas * tx.max_fee_per_gas
463
    else:
464
        if tx.gas_price < block_env.base_fee_per_gas:
465
            raise InvalidBlock
466
        effective_gas_price = tx.gas_price
467
        max_gas_fee = tx.gas * tx.gas_price
468
469
    if isinstance(tx, BlobTransaction):
470
        if not isinstance(tx.to, Address):
471
            raise TransactionTypeContractCreationError(tx)
472
        if len(tx.blob_versioned_hashes) == 0:
473
            raise NoBlobDataError("no blob data in transaction")
474
        for blob_versioned_hash in tx.blob_versioned_hashes:
475
            if blob_versioned_hash[0:1] != VERSIONED_HASH_VERSION_KZG:
476
                raise InvalidBlobVersionedHashError(
477
                    "invalid blob versioned hash"
478
                )
479
480
        blob_gas_price = calculate_blob_gas_price(block_env.excess_blob_gas)
481
        if Uint(tx.max_fee_per_blob_gas) < blob_gas_price:
482
            raise InsufficientMaxFeePerBlobGasError(
483
                "insufficient max fee per blob gas"
484
            )
485
486
        max_gas_fee += Uint(calculate_total_blob_gas(tx)) * Uint(
487
            tx.max_fee_per_blob_gas
488
        )
489
        blob_versioned_hashes = tx.blob_versioned_hashes
490
    else:
491
        blob_versioned_hashes = ()
492
    if sender_account.nonce > Uint(tx.nonce):
493
        raise NonceMismatchError("nonce too low")
494
    elif sender_account.nonce < Uint(tx.nonce):
495
        raise NonceMismatchError("nonce too high")
496
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
497
        raise InsufficientBalanceError("insufficient sender balance")
498
    if sender_account.code_hash != EMPTY_CODE_HASH:
499
        raise InvalidSenderError("not EOA")
500
423
    return sender_address, effective_gas_price
501
    return (
502
        sender_address,
503
        effective_gas_price,
504
        blob_versioned_hashes,
505
        tx_blob_gas_used,
506
    )

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:
515
    <snip>
536
    receipt = Receipt(
537
        succeeded=error is None,
538
        cumulative_gas_used=cumulative_gas_used,
539
        bloom=logs_bloom(logs),
540
        logs=logs,
541
    )
542
543
    return encode_receipt(tx, receipt)

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:
551
    <snip>
570
    system_tx_state = TransactionState(parent=block_env.state)
571
    system_contract_code = get_code(
572
        system_tx_state,
573
        get_account(system_tx_state, target_address).code_hash,
574
    )
575
576
    tx_env = vm.TransactionEnvironment(
577
        origin=SYSTEM_ADDRESS,
578
        gas_price=block_env.base_fee_per_gas,
579
        gas=SYSTEM_TRANSACTION_GAS,
580
        access_list_addresses=set(),
581
        access_list_storage_keys=set(),
582
        state=system_tx_state,
583
        blob_versioned_hashes=(),
584
        index_in_block=None,
585
        tx_hash=None,
586
    )
587
588
    system_tx_message = Message(
589
        block_env=block_env,
590
        tx_env=tx_env,
591
        caller=SYSTEM_ADDRESS,
592
        target=target_address,
593
        gas=SYSTEM_TRANSACTION_GAS,
594
        value=U256(0),
595
        data=data,
596
        code=system_contract_code,
597
        depth=Uint(0),
598
        current_target=target_address,
599
        code_address=target_address,
600
        should_transfer_value=False,
601
        is_static=False,
602
        accessed_addresses=set(),
603
        accessed_storage_keys=set(),
604
        parent_evm=None,
605
    )
606
607
    system_tx_output = process_message_call(system_tx_message)
608
609
    incorporate_tx_into_block(system_tx_state)
610
611
    return system_tx_output

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:
619
    <snip>
644
    block_output = vm.BlockOutput()
645
646
    process_unchecked_system_transaction(
647
        block_env=block_env,
648
        target_address=BEACON_ROOTS_ADDRESS,
649
        data=block_env.parent_beacon_block_root,
650
    )
651
652
    for i, tx in enumerate(map(decode_transaction, transactions)):
653
        process_transaction(block_env, block_output, tx, Uint(i))
654
655
    process_withdrawals(block_env, block_output, withdrawals)
656
657
    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:
666
    <snip>
690
    tx_state = TransactionState(parent=block_env.state)
691
692
    trie_set(
693
        block_output.transactions_trie,
694
        rlp.encode(index),
695
        encode_transaction(tx),
696
    )
697
698
    intrinsic_gas = validate_transaction(tx)
699
700
    (
701
        sender,
547
        effective_gas_price,
702
        effective_gas_price,
703
        blob_versioned_hashes,
704
        tx_blob_gas_used,
705
    ) = check_transaction(
706
        block_env=block_env,
707
        block_output=block_output,
708
        tx=tx,
709
        tx_state=tx_state,
710
    )
711
712
    sender_account = get_account(tx_state, sender)
713
714
    if isinstance(tx, BlobTransaction):
715
        blob_gas_fee = calculate_data_fee(block_env.excess_blob_gas, tx)
716
    else:
717
        blob_gas_fee = Uint(0)
718
719
    effective_gas_fee = tx.gas * effective_gas_price
720
721
    gas = tx.gas - intrinsic_gas
722
    increment_nonce(tx_state, sender)
723
724
    sender_balance_after_gas_fee = (
563
        Uint(sender_account.balance) - effective_gas_fee
725
        Uint(sender_account.balance) - effective_gas_fee - blob_gas_fee
726
    )
727
    set_account_balance(tx_state, sender, U256(sender_balance_after_gas_fee))
728
729
    access_list_addresses = set()
730
    access_list_storage_keys = set()
731
    access_list_addresses.add(block_env.coinbase)
570
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
732
    if isinstance(
733
        tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
734
    ):
735
        for access in tx.access_list:
736
            access_list_addresses.add(access.account)
737
            for slot in access.slots:
738
                access_list_storage_keys.add((access.account, slot))
739
740
    tx_env = vm.TransactionEnvironment(
741
        origin=sender,
742
        gas_price=effective_gas_price,
743
        gas=gas,
744
        access_list_addresses=access_list_addresses,
745
        access_list_storage_keys=access_list_storage_keys,
746
        state=tx_state,
747
        blob_versioned_hashes=blob_versioned_hashes,
748
        index_in_block=index,
749
        tx_hash=get_transaction_hash(encode_transaction(tx)),
750
    )
751
752
    message = prepare_message(block_env, tx_env, tx)
753
754
    tx_output = process_message_call(message)
755
756
    tx_gas_used_before_refund = tx.gas - tx_output.gas_left
757
    tx_gas_refund = min(
758
        tx_gas_used_before_refund // Uint(5), Uint(tx_output.refund_counter)
759
    )
760
    tx_gas_used_after_refund = tx_gas_used_before_refund - tx_gas_refund
761
    tx_gas_left = tx.gas - tx_gas_used_after_refund
762
    gas_refund_amount = tx_gas_left * effective_gas_price
763
764
    # For non-1559 transactions effective_gas_price == tx.gas_price
765
    priority_fee_per_gas = effective_gas_price - block_env.base_fee_per_gas
766
    transaction_fee = tx_gas_used_after_refund * priority_fee_per_gas
767
768
    # refund gas
769
    create_ether(tx_state, sender, U256(gas_refund_amount))
770
771
    # transfer miner fees
772
    create_ether(tx_state, block_env.coinbase, U256(transaction_fee))
773
774
    for address in tx_output.accounts_to_delete:
775
        destroy_account(tx_state, address)
776
777
    block_output.block_gas_used += tx_gas_used_after_refund
778
    block_output.blob_gas_used += tx_blob_gas_used
779
780
    receipt = make_receipt(
781
        tx, tx_output.error, block_output.block_gas_used, tx_output.logs
782
    )
783
784
    receipt_key = rlp.encode(Uint(index))
785
    block_output.receipt_keys += (receipt_key,)
786
787
    trie_set(
788
        block_output.receipts_trie,
789
        receipt_key,
790
        receipt,
791
    )
792
793
    block_output.block_logs += tx_output.logs
794
795
    incorporate_tx_into_block(tx_state)

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:
803
    <snip>
806
    wd_state = TransactionState(parent=block_env.state)
807
808
    for i, wd in enumerate(withdrawals):
809
        trie_set(
810
            block_output.withdrawals_trie,
811
            rlp.encode(Uint(i)),
812
            rlp.encode(wd),
813
        )
814
815
        create_ether(wd_state, wd.address, U256(wd.amount) * U256(10**9))
816
817
    incorporate_tx_into_block(wd_state)

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 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 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:
821
    <snip>
849
    max_adjustment_delta = parent_gas_limit // GasCosts.LIMIT_ADJUSTMENT_FACTOR
850
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
851
        return False
852
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
853
        return False
854
    if gas_limit < GasCosts.LIMIT_MINIMUM:
855
        return False
856
857
    return True