ethereum.forks.paris.fork

Ethereum Specification.

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Entry point for the Ethereum specification.

BASE_FEE_MAX_CHANGE_DENOMINATOR

70
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

71
ELASTICITY_MULTIPLIER = Uint(2)

EMPTY_OMMER_HASH

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

BlockChain

History and current state of the block chain.

75
@dataclass
class BlockChain:

blocks

81
    blocks: List[Block]

state

82
    state: State

chain_id

83
    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:
87
    """
88
    Transforms the state from the previous hard fork (`old`) into the block
89
    chain object for this hard fork and returns it.
90
91
    When forks need to implement an irregular state transition, this function
92
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
93
    an example.
94
95
    Parameters
96
    ----------
97
    old :
98
        Previous block chain object.
99
100
    Returns
101
    -------
102
    new : `BlockChain`
103
        Upgraded block chain object for this hard fork.
104
105
    """
106
    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]:
110
    """
111
    Obtain the list of hashes of the previous 256 blocks in order of
112
    increasing block number.
113
114
    This function will return less hashes for the first 256 blocks.
115
116
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
117
    therefore this function retrieves them.
118
119
    Parameters
120
    ----------
121
    chain :
122
        History and current state.
123
124
    Returns
125
    -------
126
    recent_block_hashes : `List[Hash32]`
127
        Hashes of the recent 256 blocks in order of increasing block number.
128
129
    """
130
    recent_blocks = chain.blocks[-255:]
131
    # TODO: This function has not been tested rigorously
132
    if len(recent_blocks) == 0:
133
        return []
134
135
    recent_block_hashes = []
136
137
    for block in recent_blocks:
138
        prev_block_hash = block.header.parent_hash
139
        recent_block_hashes.append(prev_block_hash)
140
141
    # We are computing the hash only for the most recent block and not for
142
    # the rest of the blocks as they have successors which have the hash of
143
    # the current block as parent hash.
144
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
145
    recent_block_hashes.append(most_recent_block_hash)
146
147
    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:
151
    """
152
    Attempts to apply a block to an existing block chain.
153
154
    All parts of the block's contents need to be verified before being added
155
    to the chain. Blocks are verified by ensuring that the contents of the
156
    block make logical sense with the contents of the parent block. The
157
    information in the block's header must also match the corresponding
158
    information in the block.
159
160
    To implement Ethereum, in theory clients are only required to store the
161
    most recent 255 blocks of the chain since as far as execution is
162
    concerned, only those blocks are accessed. Practically, however, clients
163
    should store more blocks to handle reorgs.
164
165
    Parameters
166
    ----------
167
    chain :
168
        History and current state.
169
    block :
170
        Block to apply to `chain`.
171
172
    """
173
    validate_header(chain, block.header)
174
    if block.ommers != ():
175
        raise InvalidBlock
176
177
    block_state = BlockState(pre_state=chain.state)
178
179
    block_env = vm.BlockEnvironment(
180
        chain_id=chain.chain_id,
181
        state=block_state,
182
        block_gas_limit=block.header.gas_limit,
183
        block_hashes=get_last_256_block_hashes(chain),
184
        coinbase=block.header.coinbase,
185
        number=block.header.number,
186
        base_fee_per_gas=block.header.base_fee_per_gas,
187
        time=block.header.timestamp,
188
        prev_randao=block.header.prev_randao,
189
    )
190
191
    block_output = apply_body(
192
        block_env=block_env,
193
        transactions=block.transactions,
194
    )
195
    block_diff = extract_block_diff(block_state)
196
    block_state_root, _ = chain.state.compute_state_root_and_trie_changes(
197
        block_diff.account_changes,
198
        block_diff.storage_changes,
199
        block_diff.storage_clears,
200
    )
201
    transactions_root = root(block_output.transactions_trie)
202
    receipt_root = root(block_output.receipts_trie)
203
    block_logs_bloom = logs_bloom(block_output.block_logs)
204
205
    if block_output.block_gas_used != block.header.gas_used:
206
        raise InvalidBlock(
207
            f"{block_output.block_gas_used} != {block.header.gas_used}"
208
        )
209
    if transactions_root != block.header.transactions_root:
210
        raise InvalidBlock
211
    if block_state_root != block.header.state_root:
212
        raise InvalidBlock
213
    if receipt_root != block.header.receipt_root:
214
        raise InvalidBlock
215
    if block_logs_bloom != block.header.bloom:
216
        raise InvalidBlock
217
218
    apply_changes_to_state(chain.state, block_diff)
219
    chain.blocks.append(block)
220
    if len(chain.blocks) > 255:
221
        # Real clients have to store more blocks to deal with reorgs, but the
222
        # protocol only requires the last 255
223
        chain.blocks = chain.blocks[-255:]

calculate_base_fee_per_gas

Calculates the base fee per gas for the block.

Parameters

block_gas_limit : Gas limit of the block for which the base fee is being calculated. parent_gas_limit : Gas limit of the parent block. parent_gas_used : Gas used in the parent block. parent_base_fee_per_gas : Base fee per gas of the parent block.

Returns

base_fee_per_gas : Uint Base fee per gas for the block.

def calculate_base_fee_per_gas(block_gas_limit: Uint, ​​parent_gas_limit: Uint, ​​parent_gas_used: Uint, ​​parent_base_fee_per_gas: Uint) -> Uint:
232
    """
233
    Calculates the base fee per gas for the block.
234
235
    Parameters
236
    ----------
237
    block_gas_limit :
238
        Gas limit of the block for which the base fee is being calculated.
239
    parent_gas_limit :
240
        Gas limit of the parent block.
241
    parent_gas_used :
242
        Gas used in the parent block.
243
    parent_base_fee_per_gas :
244
        Base fee per gas of the parent block.
245
246
    Returns
247
    -------
248
    base_fee_per_gas : `Uint`
249
        Base fee per gas for the block.
250
251
    """
252
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
253
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
254
        raise InvalidBlock
255
256
    if parent_gas_used == parent_gas_target:
257
        expected_base_fee_per_gas = parent_base_fee_per_gas
258
    elif parent_gas_used > parent_gas_target:
259
        gas_used_delta = parent_gas_used - parent_gas_target
260
261
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
262
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
263
264
        base_fee_per_gas_delta = max(
265
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
266
            Uint(1),
267
        )
268
269
        expected_base_fee_per_gas = (
270
            parent_base_fee_per_gas + base_fee_per_gas_delta
271
        )
272
    else:
273
        gas_used_delta = parent_gas_target - parent_gas_used
274
275
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
276
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
277
278
        base_fee_per_gas_delta = (
279
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
280
        )
281
282
        expected_base_fee_per_gas = (
283
            parent_base_fee_per_gas - base_fee_per_gas_delta
284
        )
285
286
    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:
290
    """
291
    Verifies a block header.
292
293
    In order to consider a block's header valid, the logic for the
294
    quantities in the header should match the logic for the block itself.
295
    For example the header timestamp should be greater than the block's parent
296
    timestamp because the block was created *after* the parent block.
297
    Additionally, the block's number should be directly following the parent
298
    block's number since it is the next block in the sequence.
299
300
    Parameters
301
    ----------
302
    chain :
303
        History and current state.
304
    header :
305
        Header to check for correctness.
306
307
    """
308
    if header.number < Uint(1):
309
        raise InvalidBlock
310
311
    parent_header = chain.blocks[-1].header
312
313
    if header.gas_used > header.gas_limit:
314
        raise InvalidBlock
315
316
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
317
        header.gas_limit,
318
        parent_header.gas_limit,
319
        parent_header.gas_used,
320
        parent_header.base_fee_per_gas,
321
    )
322
    if expected_base_fee_per_gas != header.base_fee_per_gas:
323
        raise InvalidBlock
324
    if header.timestamp <= parent_header.timestamp:
325
        raise InvalidBlock
326
    if header.number != parent_header.number + Uint(1):
327
        raise InvalidBlock
328
    if len(header.extra_data) > 32:
329
        raise InvalidBlock
330
    if header.difficulty != 0:
331
        raise InvalidBlock
332
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
333
        raise InvalidBlock
334
    if header.ommers_hash != EMPTY_OMMER_HASH:
335
        raise InvalidBlock
336
337
    block_parent_hash = keccak256(rlp.encode(parent_header))
338
    if header.parent_hash != block_parent_hash:
339
        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.

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.

def check_transaction(block_env: ethereum.forks.paris.vm.BlockEnvironment, ​​block_output: ethereum.forks.paris.vm.BlockOutput, ​​tx: Transaction, ​​tx_state: TransactionState) -> Tuple[Address, Uint]:
348
    """
349
    Check if the transaction is includable in the block.
350
351
    Parameters
352
    ----------
353
    block_env :
354
        The block scoped environment.
355
    block_output :
356
        The block output for the current block.
357
    tx :
358
        The transaction.
359
    tx_state :
360
        The transaction state tracker.
361
362
    Returns
363
    -------
364
    sender_address :
365
        The sender of the transaction.
366
    effective_gas_price :
367
        The price to charge for gas when the transaction is executed.
368
369
    Raises
370
    ------
371
    InvalidBlock :
372
        If the transaction is not includable.
373
    GasUsedExceedsLimitError :
374
        If the gas used by the transaction exceeds the block's gas limit.
375
    NonceMismatchError :
376
        If the nonce of the transaction is not equal to the sender's nonce.
377
    InsufficientBalanceError :
378
        If the sender's balance is not enough to pay for the transaction.
379
    InvalidSenderError :
380
        If the transaction is from an address that does not exist anymore.
381
    PriorityFeeGreaterThanMaxFeeError :
382
        If the priority fee is greater than the maximum fee per gas.
383
    InsufficientMaxFeePerGasError :
384
        If the maximum fee per gas is insufficient for the transaction.
385
386
    """
387
    gas_available = block_env.block_gas_limit - block_output.block_gas_used
388
    if tx.gas > gas_available:
389
        raise GasUsedExceedsLimitError("gas used exceeds limit")
390
    sender_address = recover_sender(block_env.chain_id, tx)
391
    sender_account = get_account(tx_state, sender_address)
392
393
    if isinstance(tx, FeeMarketTransaction):
394
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
395
            raise PriorityFeeGreaterThanMaxFeeError(
396
                "priority fee greater than max fee"
397
            )
398
        if tx.max_fee_per_gas < block_env.base_fee_per_gas:
399
            raise InsufficientMaxFeePerGasError(
400
                tx.max_fee_per_gas, block_env.base_fee_per_gas
401
            )
402
403
        priority_fee_per_gas = min(
404
            tx.max_priority_fee_per_gas,
405
            tx.max_fee_per_gas - block_env.base_fee_per_gas,
406
        )
407
        effective_gas_price = priority_fee_per_gas + block_env.base_fee_per_gas
408
        max_gas_fee = tx.gas * tx.max_fee_per_gas
409
    else:
410
        if tx.gas_price < block_env.base_fee_per_gas:
411
            raise InvalidBlock
412
        effective_gas_price = tx.gas_price
413
        max_gas_fee = tx.gas * tx.gas_price
414
415
    if sender_account.nonce > Uint(tx.nonce):
416
        raise NonceMismatchError("nonce too low")
417
    elif sender_account.nonce < Uint(tx.nonce):
418
        raise NonceMismatchError("nonce too high")
419
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
420
        raise InsufficientBalanceError("insufficient sender balance")
421
    if sender_account.code_hash != EMPTY_CODE_HASH:
422
        raise InvalidSenderError("not EOA")
423
424
    return sender_address, effective_gas_price

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:
433
    """
434
    Make the receipt for a transaction that was executed.
435
436
    Parameters
437
    ----------
438
    tx :
439
        The executed transaction.
440
    error :
441
        Error in the top level frame of the transaction, if any.
442
    cumulative_gas_used :
443
        The total gas used so far in the block after the transaction was
444
        executed.
445
    logs :
446
        The logs produced by the transaction.
447
448
    Returns
449
    -------
450
    receipt :
451
        The receipt for the transaction.
452
453
    """
454
    receipt = Receipt(
455
        succeeded=error is None,
456
        cumulative_gas_used=cumulative_gas_used,
457
        bloom=logs_bloom(logs),
458
        logs=logs,
459
    )
460
461
    return encode_receipt(tx, receipt)

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. transactions : Transactions included in the block.

Returns

block_output : The block output for the current block.

def apply_body(block_env: ethereum.forks.paris.vm.BlockEnvironment, ​​transactions: Tuple[LegacyTransaction | Bytes, ...]) -> ethereum.forks.paris.vm.BlockOutput:
468
    """
469
    Executes a block.
470
471
    Many of the contents of a block are stored in data structures called
472
    tries. There is a transactions trie which is similar to a ledger of the
473
    transactions stored in the current block. There is also a receipts trie
474
    which stores the results of executing a transaction, like the post state
475
    and gas used. This function creates and executes the block that is to be
476
    added to the chain.
477
478
    Parameters
479
    ----------
480
    block_env :
481
        The block scoped environment.
482
    transactions :
483
        Transactions included in the block.
484
485
    Returns
486
    -------
487
    block_output :
488
        The block output for the current block.
489
490
    """
491
    block_output = vm.BlockOutput()
492
493
    for i, tx in enumerate(map(decode_transaction, transactions)):
494
        process_transaction(block_env, block_output, tx, Uint(i))
495
496
    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.paris.vm.BlockEnvironment, ​​block_output: ethereum.forks.paris.vm.BlockOutput, ​​tx: Transaction, ​​index: Uint) -> None:
505
    """
506
    Execute a transaction against the provided environment.
507
508
    This function processes the actions needed to execute a transaction.
509
    It decrements the sender's account balance after calculating the gas fee
510
    and refunds them the proper amount after execution. Calling contracts,
511
    deploying code, and incrementing nonces are all examples of actions that
512
    happen within this function or from a call made within this function.
513
514
    Accounts that are marked for deletion are processed and destroyed after
515
    execution.
516
517
    Parameters
518
    ----------
519
    block_env :
520
        Environment for the Ethereum Virtual Machine.
521
    block_output :
522
        The block output for the current block.
523
    tx :
524
        Transaction to execute.
525
    index:
526
        Index of the transaction in the block.
527
528
    """
529
    tx_state = TransactionState(parent=block_env.state)
530
531
    trie_set(
532
        block_output.transactions_trie,
533
        rlp.encode(index),
534
        encode_transaction(tx),
535
    )
536
537
    intrinsic_gas = validate_transaction(tx)
538
539
    (
540
        sender,
541
        effective_gas_price,
542
    ) = check_transaction(
543
        block_env=block_env,
544
        block_output=block_output,
545
        tx=tx,
546
        tx_state=tx_state,
547
    )
548
549
    sender_account = get_account(tx_state, sender)
550
551
    effective_gas_fee = tx.gas * effective_gas_price
552
553
    gas = tx.gas - intrinsic_gas
554
    increment_nonce(tx_state, sender)
555
556
    sender_balance_after_gas_fee = (
557
        Uint(sender_account.balance) - effective_gas_fee
558
    )
559
    set_account_balance(tx_state, sender, U256(sender_balance_after_gas_fee))
560
561
    access_list_addresses = set()
562
    access_list_storage_keys = set()
563
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
564
        for access in tx.access_list:
565
            access_list_addresses.add(access.account)
566
            for slot in access.slots:
567
                access_list_storage_keys.add((access.account, slot))
568
569
    tx_env = vm.TransactionEnvironment(
570
        origin=sender,
571
        gas_price=effective_gas_price,
572
        gas=gas,
573
        access_list_addresses=access_list_addresses,
574
        access_list_storage_keys=access_list_storage_keys,
575
        state=tx_state,
576
        index_in_block=index,
577
        tx_hash=get_transaction_hash(encode_transaction(tx)),
578
    )
579
580
    message = prepare_message(block_env, tx_env, tx)
581
582
    tx_output = process_message_call(message)
583
584
    tx_gas_used_before_refund = tx.gas - tx_output.gas_left
585
    tx_gas_refund = min(
586
        tx_gas_used_before_refund // Uint(5), Uint(tx_output.refund_counter)
587
    )
588
    tx_gas_used_after_refund = tx_gas_used_before_refund - tx_gas_refund
589
    tx_gas_left = tx.gas - tx_gas_used_after_refund
590
    gas_refund_amount = tx_gas_left * effective_gas_price
591
592
    # For non-1559 transactions effective_gas_price == tx.gas_price
593
    priority_fee_per_gas = effective_gas_price - block_env.base_fee_per_gas
594
    transaction_fee = tx_gas_used_after_refund * priority_fee_per_gas
595
596
    # refund gas
597
    sender_balance_after_refund = get_account(tx_state, sender).balance + U256(
598
        gas_refund_amount
599
    )
600
    set_account_balance(tx_state, sender, sender_balance_after_refund)
601
602
    # transfer miner fees
603
    coinbase_balance_after_mining_fee = get_account(
604
        tx_state, block_env.coinbase
605
    ).balance + U256(transaction_fee)
606
    set_account_balance(
607
        tx_state, block_env.coinbase, coinbase_balance_after_mining_fee
608
    )
609
610
    for address in tx_output.accounts_to_delete:
611
        destroy_account(tx_state, address)
612
613
    block_output.block_gas_used += tx_gas_used_after_refund
614
615
    receipt = make_receipt(
616
        tx, tx_output.error, block_output.block_gas_used, tx_output.logs
617
    )
618
619
    receipt_key = rlp.encode(Uint(index))
620
    block_output.receipt_keys += (receipt_key,)
621
622
    trie_set(
623
        block_output.receipts_trie,
624
        receipt_key,
625
        receipt,
626
    )
627
628
    block_output.block_logs += tx_output.logs
629
630
    incorporate_tx_into_block(tx_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:
634
    """
635
    Validates the gas limit for a block.
636
637
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
638
    quotient of the parent block's gas limit and the
639
    ``LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
640
    passed through as a parameter is greater than or equal to the *sum* of
641
    the parent's gas and the adjustment delta then the limit for gas is too
642
    high and fails this function's check. Similarly, if the limit is less
643
    than or equal to the *difference* of the parent's gas and the adjustment
644
    delta *or* the predefined ``LIMIT_MINIMUM`` then this function's
645
    check fails because the gas limit doesn't allow for a sufficient or
646
    reasonable amount of gas to be used on a block.
647
648
    Parameters
649
    ----------
650
    gas_limit :
651
        Gas limit to validate.
652
653
    parent_gas_limit :
654
        Gas limit of the parent block.
655
656
    Returns
657
    -------
658
    check : `bool`
659
        True if gas limit constraints are satisfied, False otherwise.
660
661
    """
662
    max_adjustment_delta = parent_gas_limit // GasCosts.LIMIT_ADJUSTMENT_FACTOR
663
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
664
        return False
665
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
666
        return False
667
    if gas_limit < GasCosts.LIMIT_MINIMUM:
668
        return False
669
670
    return True