ethereum.paris.forkethereum.shanghai.fork

Ethereum Specification ^^^^^^^^^^^^^^^^^^^^^^

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

Introduction

Entry point for the Ethereum specification.

BASE_FEE_MAX_CHANGE_DENOMINATOR

58
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

59
ELASTICITY_MULTIPLIER = Uint(2)

GAS_LIMIT_ADJUSTMENT_FACTOR

60
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

61
GAS_LIMIT_MINIMUM = Uint(5000)

EMPTY_OMMER_HASH

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

BlockChain

History and current state of the block chain.

65
@dataclass
class BlockChain:

blocks

71
    blocks: List[Block]

state

72
    state: State

chain_id

73
    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:
77
    """
78
    Transforms the state from the previous hard fork (`old`) into the block
79
    chain object for this hard fork and returns it.
80
81
    When forks need to implement an irregular state transition, this function
82
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
83
    an example.
84
85
    Parameters
86
    ----------
87
    old :
88
        Previous block chain object.
89
90
    Returns
91
    -------
92
    new : `BlockChain`
93
        Upgraded block chain object for this hard fork.
94
    """
95
    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]:
99
    """
100
    Obtain the list of hashes of the previous 256 blocks in order of
101
    increasing block number.
102
103
    This function will return less hashes for the first 256 blocks.
104
105
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
106
    therefore this function retrieves them.
107
108
    Parameters
109
    ----------
110
    chain :
111
        History and current state.
112
113
    Returns
114
    -------
115
    recent_block_hashes : `List[Hash32]`
116
        Hashes of the recent 256 blocks in order of increasing block number.
117
    """
118
    recent_blocks = chain.blocks[-255:]
119
    # TODO: This function has not been tested rigorously
120
    if len(recent_blocks) == 0:
121
        return []
122
123
    recent_block_hashes = []
124
125
    for block in recent_blocks:
126
        prev_block_hash = block.header.parent_hash
127
        recent_block_hashes.append(prev_block_hash)
128
129
    # We are computing the hash only for the most recent block and not for
130
    # the rest of the blocks as they have successors which have the hash of
131
    # the current block as parent hash.
132
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
133
    recent_block_hashes.append(most_recent_block_hash)
134
135
    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:
139
    """
140
    Attempts to apply a block to an existing block chain.
141
142
    All parts of the block's contents need to be verified before being added
143
    to the chain. Blocks are verified by ensuring that the contents of the
144
    block make logical sense with the contents of the parent block. The
145
    information in the block's header must also match the corresponding
146
    information in the block.
147
148
    To implement Ethereum, in theory clients are only required to store the
149
    most recent 255 blocks of the chain since as far as execution is
150
    concerned, only those blocks are accessed. Practically, however, clients
151
    should store more blocks to handle reorgs.
152
153
    Parameters
154
    ----------
155
    chain :
156
        History and current state.
157
    block :
158
        Block to apply to `chain`.
159
    """
160
    validate_header(chain, block.header)
161
    if block.ommers != ():
162
        raise InvalidBlock
163
164
    block_env = vm.BlockEnvironment(
165
        chain_id=chain.chain_id,
166
        state=chain.state,
167
        block_gas_limit=block.header.gas_limit,
168
        block_hashes=get_last_256_block_hashes(chain),
169
        coinbase=block.header.coinbase,
170
        number=block.header.number,
171
        base_fee_per_gas=block.header.base_fee_per_gas,
172
        time=block.header.timestamp,
173
        prev_randao=block.header.prev_randao,
174
    )
175
176
    block_output = apply_body(
177
        block_env=block_env,
178
        transactions=block.transactions,
179
        withdrawals=block.withdrawals,
180
    )
181
    block_state_root = state_root(block_env.state)
182
    transactions_root = root(block_output.transactions_trie)
183
    receipt_root = root(block_output.receipts_trie)
184
    block_logs_bloom = logs_bloom(block_output.block_logs)
185
    withdrawals_root = root(block_output.withdrawals_trie)
186
187
    if block_output.block_gas_used != block.header.gas_used:
188
        raise InvalidBlock(
189
            f"{block_output.block_gas_used} != {block.header.gas_used}"
190
        )
191
    if transactions_root != block.header.transactions_root:
192
        raise InvalidBlock
193
    if block_state_root != block.header.state_root:
194
        raise InvalidBlock
195
    if receipt_root != block.header.receipt_root:
196
        raise InvalidBlock
197
    if block_logs_bloom != block.header.bloom:
198
        raise InvalidBlock
199
    if withdrawals_root != block.header.withdrawals_root:
200
        raise InvalidBlock
201
202
    chain.blocks.append(block)
203
    if len(chain.blocks) > 255:
204
        # Real clients have to store more blocks to deal with reorgs, but the
205
        # protocol only requires the last 255
206
        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:
215
    """
216
    Calculates the base fee per gas for the block.
217
218
    Parameters
219
    ----------
220
    block_gas_limit :
221
        Gas limit of the block for which the base fee is being calculated.
222
    parent_gas_limit :
223
        Gas limit of the parent block.
224
    parent_gas_used :
225
        Gas used in the parent block.
226
    parent_base_fee_per_gas :
227
        Base fee per gas of the parent block.
228
229
    Returns
230
    -------
231
    base_fee_per_gas : `Uint`
232
        Base fee per gas for the block.
233
    """
234
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
235
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
236
        raise InvalidBlock
237
238
    if parent_gas_used == parent_gas_target:
239
        expected_base_fee_per_gas = parent_base_fee_per_gas
240
    elif parent_gas_used > parent_gas_target:
241
        gas_used_delta = parent_gas_used - parent_gas_target
242
243
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
244
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
245
246
        base_fee_per_gas_delta = max(
247
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
248
            Uint(1),
249
        )
250
251
        expected_base_fee_per_gas = (
252
            parent_base_fee_per_gas + base_fee_per_gas_delta
253
        )
254
    else:
255
        gas_used_delta = parent_gas_target - parent_gas_used
256
257
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
258
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
259
260
        base_fee_per_gas_delta = (
261
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
262
        )
263
264
        expected_base_fee_per_gas = (
265
            parent_base_fee_per_gas - base_fee_per_gas_delta
266
        )
267
268
    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:
272
    """
273
    Verifies a block header.
274
275
    In order to consider a block's header valid, the logic for the
276
    quantities in the header should match the logic for the block itself.
277
    For example the header timestamp should be greater than the block's parent
278
    timestamp because the block was created *after* the parent block.
279
    Additionally, the block's number should be directly following the parent
280
    block's number since it is the next block in the sequence.
281
282
    Parameters
283
    ----------
284
    chain :
285
        History and current state.
286
    header :
287
        Header to check for correctness.
288
    """
289
    if header.number < Uint(1):
290
        raise InvalidBlock
291
292
    parent_header = chain.blocks[-1].header
293
294
    if header.gas_used > header.gas_limit:
295
        raise InvalidBlock
296
297
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
298
        header.gas_limit,
299
        parent_header.gas_limit,
300
        parent_header.gas_used,
301
        parent_header.base_fee_per_gas,
302
    )
303
    if expected_base_fee_per_gas != header.base_fee_per_gas:
304
        raise InvalidBlock
305
    if header.timestamp <= parent_header.timestamp:
306
        raise InvalidBlock
307
    if header.number != parent_header.number + Uint(1):
308
        raise InvalidBlock
309
    if len(header.extra_data) > 32:
310
        raise InvalidBlock
311
    if header.difficulty != 0:
312
        raise InvalidBlock
313
    if header.nonce != b"\x00\x00\x00\x00\x00\x00\x00\x00":
314
        raise InvalidBlock
315
    if header.ommers_hash != EMPTY_OMMER_HASH:
316
        raise InvalidBlock
317
318
    block_parent_hash = keccak256(rlp.encode(parent_header))
319
    if header.parent_hash != block_parent_hash:
320
        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.

Raises

InvalidBlock : If the transaction is not includable.

def check_transaction(block_env: ethereum.paris.vm.BlockEnvironmentethereum.shanghai.vm.BlockEnvironment, ​​block_output: ethereum.paris.vm.BlockOutputethereum.shanghai.vm.BlockOutput, ​​tx: Transaction) -> Tuple[Address, Uint]:
328
    """
329
    Check if the transaction is includable in the block.
330
331
    Parameters
332
    ----------
333
    block_env :
334
        The block scoped environment.
335
    block_output :
336
        The block output for the current block.
337
    tx :
338
        The transaction.
339
340
    Returns
341
    -------
342
    sender_address :
343
        The sender of the transaction.
344
    effective_gas_price :
345
        The price to charge for gas when the transaction is executed.
346
347
    Raises
348
    ------
349
    InvalidBlock :
350
        If the transaction is not includable.
351
    """
352
    gas_available = block_env.block_gas_limit - block_output.block_gas_used
353
    if tx.gas > gas_available:
354
        raise InvalidBlock
355
    sender_address = recover_sender(block_env.chain_id, tx)
356
    sender_account = get_account(block_env.state, sender_address)
357
358
    if isinstance(tx, FeeMarketTransaction):
359
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
360
            raise InvalidBlock
361
        if tx.max_fee_per_gas < block_env.base_fee_per_gas:
362
            raise InvalidBlock
363
364
        priority_fee_per_gas = min(
365
            tx.max_priority_fee_per_gas,
366
            tx.max_fee_per_gas - block_env.base_fee_per_gas,
367
        )
368
        effective_gas_price = priority_fee_per_gas + block_env.base_fee_per_gas
369
        max_gas_fee = tx.gas * tx.max_fee_per_gas
370
    else:
371
        if tx.gas_price < block_env.base_fee_per_gas:
372
            raise InvalidBlock
373
        effective_gas_price = tx.gas_price
374
        max_gas_fee = tx.gas * tx.gas_price
375
376
    if sender_account.nonce != tx.nonce:
377
        raise InvalidBlock
378
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
379
        raise InvalidBlock
380
    if sender_account.code:
381
        raise InvalidSenderError("not EOA")
382
383
    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, ...]) -> Union[Bytes, Receipt]:
392
    """
393
    Make the receipt for a transaction that was executed.
394
395
    Parameters
396
    ----------
397
    tx :
398
        The executed transaction.
399
    error :
400
        Error in the top level frame of the transaction, if any.
401
    cumulative_gas_used :
402
        The total gas used so far in the block after the transaction was
403
        executed.
404
    logs :
405
        The logs produced by the transaction.
406
407
    Returns
408
    -------
409
    receipt :
410
        The receipt for the transaction.
411
    """
412
    receipt = Receipt(
413
        succeeded=error is None,
414
        cumulative_gas_used=cumulative_gas_used,
415
        bloom=logs_bloom(logs),
416
        logs=logs,
417
    )
418
419
    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. 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.paris.vm.BlockEnvironmentethereum.shanghai.vm.BlockEnvironment, ​​transactions: Tuple[Union[LegacyTransaction, Bytes], ...], ​​withdrawals: Tuple[Withdrawal, ...]) -> ethereum.paris.vm.BlockOutputethereum.shanghai.vm.BlockOutput:
427
    """
428
    Executes a block.
429
430
    Many of the contents of a block are stored in data structures called
431
    tries. There is a transactions trie which is similar to a ledger of the
432
    transactions stored in the current block. There is also a receipts trie
433
    which stores the results of executing a transaction, like the post state
434
    and gas used. This function creates and executes the block that is to be
435
    added to the chain.
436
437
    Parameters
438
    ----------
439
    block_env :
440
        The block scoped environment.
441
    block_output :
442
        The block output for the current block.
443
    transactions :
444
        Transactions included in the block.
445
    withdrawals :
446
        Withdrawals to be processed in the current block.
447
448
    Returns
449
    -------
450
    block_output :
451
        The block output for the current block.
452
    """
453
    block_output = vm.BlockOutput()
454
455
    for i, tx in enumerate(map(decode_transaction, transactions)):
456
        process_transaction(block_env, block_output, tx, Uint(i))
457
458
    process_withdrawals(block_env, block_output, withdrawals)
459
460
    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.paris.vm.BlockEnvironmentethereum.shanghai.vm.BlockEnvironment, ​​block_output: ethereum.paris.vm.BlockOutputethereum.shanghai.vm.BlockOutput, ​​tx: Transaction, ​​index: Uint) -> None:
469
    """
470
    Execute a transaction against the provided environment.
471
472
    This function processes the actions needed to execute a transaction.
473
    It decrements the sender's account after calculating the gas fee and
474
    refunds them the proper amount after execution. Calling contracts,
475
    deploying code, and incrementing nonces are all examples of actions that
476
    happen within this function or from a call made within this function.
477
478
    Accounts that are marked for deletion are processed and destroyed after
479
    execution.
480
481
    Parameters
482
    ----------
483
    block_env :
484
        Environment for the Ethereum Virtual Machine.
485
    block_output :
486
        The block output for the current block.
487
    tx :
488
        Transaction to execute.
489
    index:
490
        Index of the transaction in the block.
491
    """
492
    trie_set(
493
        block_output.transactions_trie,
494
        rlp.encode(index),
495
        encode_transaction(tx),
496
    )
497
498
    intrinsic_gas = validate_transaction(tx)
499
500
    (
501
        sender,
502
        effective_gas_price,
503
    ) = check_transaction(
504
        block_env=block_env,
505
        block_output=block_output,
506
        tx=tx,
507
    )
508
509
    sender_account = get_account(block_env.state, sender)
510
511
    effective_gas_fee = tx.gas * effective_gas_price
512
513
    gas = tx.gas - intrinsic_gas
514
    increment_nonce(block_env.state, sender)
515
516
    sender_balance_after_gas_fee = (
517
        Uint(sender_account.balance) - effective_gas_fee
518
    )
519
    set_account_balance(
520
        block_env.state, sender, U256(sender_balance_after_gas_fee)
521
    )
522
523
    access_list_addresses = set()
524
    access_list_storage_keys = set()
525
    access_list_addresses.add(block_env.coinbase)
526
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
527
        for access in tx.access_list:
528
            access_list_addresses.add(access.account)
529
            for slot in access.slots:
530
                access_list_storage_keys.add((access.account, slot))
531
532
    tx_env = vm.TransactionEnvironment(
533
        origin=sender,
534
        gas_price=effective_gas_price,
535
        gas=gas,
536
        access_list_addresses=access_list_addresses,
537
        access_list_storage_keys=access_list_storage_keys,
538
        index_in_block=index,
539
        tx_hash=get_transaction_hash(encode_transaction(tx)),
540
        traces=[],
541
    )
542
543
    message = prepare_message(block_env, tx_env, tx)
544
545
    tx_output = process_message_call(message)
546
547
    tx_gas_used_before_refund = tx.gas - tx_output.gas_left
548
    tx_gas_refund = min(
549
        tx_gas_used_before_refund // Uint(5), Uint(tx_output.refund_counter)
550
    )
551
    tx_gas_used_after_refund = tx_gas_used_before_refund - tx_gas_refund
552
    tx_gas_left = tx.gas - tx_gas_used_after_refund
553
    gas_refund_amount = tx_gas_left * effective_gas_price
554
555
    # For non-1559 transactions effective_gas_price == tx.gas_price
556
    priority_fee_per_gas = effective_gas_price - block_env.base_fee_per_gas
557
    transaction_fee = tx_gas_used_after_refund * priority_fee_per_gas
558
559
    # refund gas
560
    sender_balance_after_refund = get_account(
561
        block_env.state, sender
562
    ).balance + U256(gas_refund_amount)
563
    set_account_balance(block_env.state, sender, sender_balance_after_refund)
564
565
    # transfer miner fees
566
    coinbase_balance_after_mining_fee = get_account(
567
        block_env.state, block_env.coinbase
568
    ).balance + U256(transaction_fee)
569
    if coinbase_balance_after_mining_fee != 0:
570
        set_account_balance(
571
            block_env.state,
572
            block_env.coinbase,
573
            coinbase_balance_after_mining_fee,
574
        )
575
    elif account_exists_and_is_empty(block_env.state, block_env.coinbase):
576
        destroy_account(block_env.state, block_env.coinbase)
577
578
    for address in tx_output.accounts_to_delete:
579
        destroy_account(block_env.state, address)
580
581
    block_output.block_gas_used += tx_gas_used_after_refund
582
583
    receipt = make_receipt(
584
        tx, tx_output.error, block_output.block_gas_used, tx_output.logs
585
    )
586
587
    receipt_key = rlp.encode(Uint(index))
588
    block_output.receipt_keys += (receipt_key,)
589
590
    trie_set(
591
        block_output.receipts_trie,
592
        receipt_key,
593
        receipt,
594
    )
595
596
    block_output.block_logs += tx_output.logs

process_withdrawals

Increase the balance of the withdrawing account.

def process_withdrawals(block_env: ethereum.shanghai.vm.BlockEnvironment, ​​block_output: ethereum.shanghai.vm.BlockOutput, ​​withdrawals: Tuple[Withdrawal, ...]) -> None:
604
    """
605
    Increase the balance of the withdrawing account.
606
    """
607
608
    def increase_recipient_balance(recipient: Account) -> None:
609
        recipient.balance += wd.amount * U256(10**9)
610
611
    for i, wd in enumerate(withdrawals):
612
        trie_set(
613
            block_output.withdrawals_trie,
614
            rlp.encode(Uint(i)),
615
            rlp.encode(wd),
616
        )
617
618
        modify_state(block_env.state, wd.address, increase_recipient_balance)
619
620
        if account_exists_and_is_empty(block_env.state, wd.address):
621
            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:
625
    """
626
    Validates the gas limit for a block.
627
628
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
629
    quotient of the parent block's gas limit and the
630
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
631
    passed through as a parameter is greater than or equal to the *sum* of
632
    the parent's gas and the adjustment delta then the limit for gas is too
633
    high and fails this function's check. Similarly, if the limit is less
634
    than or equal to the *difference* of the parent's gas and the adjustment
635
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
636
    check fails because the gas limit doesn't allow for a sufficient or
637
    reasonable amount of gas to be used on a block.
638
639
    Parameters
640
    ----------
641
    gas_limit :
642
        Gas limit to validate.
643
644
    parent_gas_limit :
645
        Gas limit of the parent block.
646
647
    Returns
648
    -------
649
    check : `bool`
650
        True if gas limit constraints are satisfied, False otherwise.
651
    """
652
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
653
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
654
        return False
655
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
656
        return False
657
    if gas_limit < GAS_LIMIT_MINIMUM:
658
        return False
659
660
    return True