ethereum.arrow_glacier.fork

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

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

Introduction

Entry point for the Ethereum specification.

BLOCK_REWARD

58
BLOCK_REWARD = U256(2 * 10**18)

BASE_FEE_MAX_CHANGE_DENOMINATOR

59
BASE_FEE_MAX_CHANGE_DENOMINATOR = 8

ELASTICITY_MULTIPLIER

60
ELASTICITY_MULTIPLIER = 2

GAS_LIMIT_ADJUSTMENT_FACTOR

61
GAS_LIMIT_ADJUSTMENT_FACTOR = 1024

GAS_LIMIT_MINIMUM

62
GAS_LIMIT_MINIMUM = 5000

MINIMUM_DIFFICULTY

63
MINIMUM_DIFFICULTY = Uint(131072)

MAX_OMMER_DEPTH

64
MAX_OMMER_DEPTH = 6

BOMB_DELAY_BLOCKS

65
BOMB_DELAY_BLOCKS = 10700000

EMPTY_OMMER_HASH

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

BlockChain

History and current state of the block chain.

69
@dataclass
class BlockChain:

blocks

75
    blocks: List[Block]

state

76
    state: State

chain_id

77
    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:
81
    """
82
    Transforms the state from the previous hard fork (`old`) into the block
83
    chain object for this hard fork and returns it.
84
85
    When forks need to implement an irregular state transition, this function
86
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
87
    an example.
88
89
    Parameters
90
    ----------
91
    old :
92
        Previous block chain object.
93
94
    Returns
95
    -------
96
    new : `BlockChain`
97
        Upgraded block chain object for this hard fork.
98
    """
99
    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]:
103
    """
104
    Obtain the list of hashes of the previous 256 blocks in order of
105
    increasing block number.
106
107
    This function will return less hashes for the first 256 blocks.
108
109
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
110
    therefore this function retrieves them.
111
112
    Parameters
113
    ----------
114
    chain :
115
        History and current state.
116
117
    Returns
118
    -------
119
    recent_block_hashes : `List[Hash32]`
120
        Hashes of the recent 256 blocks in order of increasing block number.
121
    """
122
    recent_blocks = chain.blocks[-255:]
123
    # TODO: This function has not been tested rigorously
124
    if len(recent_blocks) == 0:
125
        return []
126
127
    recent_block_hashes = []
128
129
    for block in recent_blocks:
130
        prev_block_hash = block.header.parent_hash
131
        recent_block_hashes.append(prev_block_hash)
132
133
    # We are computing the hash only for the most recent block and not for
134
    # the rest of the blocks as they have successors which have the hash of
135
    # the current block as parent hash.
136
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
137
    recent_block_hashes.append(most_recent_block_hash)
138
139
    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:
143
    """
144
    Attempts to apply a block to an existing block chain.
145
146
    All parts of the block's contents need to be verified before being added
147
    to the chain. Blocks are verified by ensuring that the contents of the
148
    block make logical sense with the contents of the parent block. The
149
    information in the block's header must also match the corresponding
150
    information in the block.
151
152
    To implement Ethereum, in theory clients are only required to store the
153
    most recent 255 blocks of the chain since as far as execution is
154
    concerned, only those blocks are accessed. Practically, however, clients
155
    should store more blocks to handle reorgs.
156
157
    Parameters
158
    ----------
159
    chain :
160
        History and current state.
161
    block :
162
        Block to apply to `chain`.
163
    """
164
    parent_header = chain.blocks[-1].header
165
    validate_header(block.header, parent_header)
166
    validate_ommers(block.ommers, block.header, chain)
167
    apply_body_output = apply_body(
168
        chain.state,
169
        get_last_256_block_hashes(chain),
170
        block.header.coinbase,
171
        block.header.number,
172
        block.header.base_fee_per_gas,
173
        block.header.gas_limit,
174
        block.header.timestamp,
175
        block.header.difficulty,
176
        block.transactions,
177
        block.ommers,
178
        chain.chain_id,
179
    )
180
    if apply_body_output.block_gas_used != block.header.gas_used:
181
        raise InvalidBlock
182
    if apply_body_output.transactions_root != block.header.transactions_root:
183
        raise InvalidBlock
184
    if apply_body_output.state_root != block.header.state_root:
185
        raise InvalidBlock
186
    if apply_body_output.receipt_root != block.header.receipt_root:
187
        raise InvalidBlock
188
    if apply_body_output.block_logs_bloom != block.header.bloom:
189
        raise InvalidBlock
190
191
    chain.blocks.append(block)
192
    if len(chain.blocks) > 255:
193
        # Real clients have to store more blocks to deal with reorgs, but the
194
        # protocol only requires the last 255
195
        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:
204
    """
205
    Calculates the base fee per gas for the block.
206
207
    Parameters
208
    ----------
209
    block_gas_limit :
210
        Gas limit of the block for which the base fee is being calculated.
211
    parent_gas_limit :
212
        Gas limit of the parent block.
213
    parent_gas_used :
214
        Gas used in the parent block.
215
    parent_base_fee_per_gas :
216
        Base fee per gas of the parent block.
217
218
    Returns
219
    -------
220
    base_fee_per_gas : `Uint`
221
        Base fee per gas for the block.
222
    """
223
    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
224
    if not check_gas_limit(block_gas_limit, parent_gas_limit):
225
        raise InvalidBlock
226
227
    if parent_gas_used == parent_gas_target:
228
        expected_base_fee_per_gas = parent_base_fee_per_gas
229
    elif parent_gas_used > parent_gas_target:
230
        gas_used_delta = parent_gas_used - parent_gas_target
231
232
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
233
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
234
235
        base_fee_per_gas_delta = max(
236
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
237
            1,
238
        )
239
240
        expected_base_fee_per_gas = (
241
            parent_base_fee_per_gas + base_fee_per_gas_delta
242
        )
243
    else:
244
        gas_used_delta = parent_gas_target - parent_gas_used
245
246
        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
247
        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
248
249
        base_fee_per_gas_delta = (
250
            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
251
        )
252
253
        expected_base_fee_per_gas = (
254
            parent_base_fee_per_gas - base_fee_per_gas_delta
255
        )
256
257
    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

header : Header to check for correctness. parent_header : Parent Header of the header to check for correctness

def validate_header(header: Header, ​​parent_header: Header) -> None:
261
    """
262
    Verifies a block header.
263
264
    In order to consider a block's header valid, the logic for the
265
    quantities in the header should match the logic for the block itself.
266
    For example the header timestamp should be greater than the block's parent
267
    timestamp because the block was created *after* the parent block.
268
    Additionally, the block's number should be directly following the parent
269
    block's number since it is the next block in the sequence.
270
271
    Parameters
272
    ----------
273
    header :
274
        Header to check for correctness.
275
    parent_header :
276
        Parent Header of the header to check for correctness
277
    """
278
    if header.gas_used > header.gas_limit:
279
        raise InvalidBlock
280
281
    expected_base_fee_per_gas = calculate_base_fee_per_gas(
282
        header.gas_limit,
283
        parent_header.gas_limit,
284
        parent_header.gas_used,
285
        parent_header.base_fee_per_gas,
286
    )
287
    if expected_base_fee_per_gas != header.base_fee_per_gas:
288
        raise InvalidBlock
289
290
    parent_has_ommers = parent_header.ommers_hash != EMPTY_OMMER_HASH
291
    if header.timestamp <= parent_header.timestamp:
292
        raise InvalidBlock
293
    if header.number != parent_header.number + 1:
294
        raise InvalidBlock
295
    if len(header.extra_data) > 32:
296
        raise InvalidBlock
297
298
    block_difficulty = calculate_block_difficulty(
299
        header.number,
300
        header.timestamp,
301
        parent_header.timestamp,
302
        parent_header.difficulty,
303
        parent_has_ommers,
304
    )
305
    if header.difficulty != block_difficulty:
306
        raise InvalidBlock
307
308
    block_parent_hash = keccak256(rlp.encode(parent_header))
309
    if header.parent_hash != block_parent_hash:
310
        raise InvalidBlock
311
312
    validate_proof_of_work(header)

generate_header_hash_for_pow

Generate rlp hash of the header which is to be used for Proof-of-Work verification.

In other words, the PoW artefacts mix_digest and nonce are ignored while calculating this hash.

A particular PoW is valid for a single hash, that hash is computed by this function. The nonce and mix_digest are omitted from this hash because they are being changed by miners in their search for a sufficient proof-of-work.

Parameters

header : The header object for which the hash is to be generated.

Returns

hash : Hash32 The PoW valid rlp hash of the passed in header.

def generate_header_hash_for_pow(header: Header) -> Hash32:
316
    """
317
    Generate rlp hash of the header which is to be used for Proof-of-Work
318
    verification.
319
320
    In other words, the PoW artefacts `mix_digest` and `nonce` are ignored
321
    while calculating this hash.
322
323
    A particular PoW is valid for a single hash, that hash is computed by
324
    this function. The `nonce` and `mix_digest` are omitted from this hash
325
    because they are being changed by miners in their search for a sufficient
326
    proof-of-work.
327
328
    Parameters
329
    ----------
330
    header :
331
        The header object for which the hash is to be generated.
332
333
    Returns
334
    -------
335
    hash : `Hash32`
336
        The PoW valid rlp hash of the passed in header.
337
    """
338
    header_data_without_pow_artefacts = (
339
        header.parent_hash,
340
        header.ommers_hash,
341
        header.coinbase,
342
        header.state_root,
343
        header.transactions_root,
344
        header.receipt_root,
345
        header.bloom,
346
        header.difficulty,
347
        header.number,
348
        header.gas_limit,
349
        header.gas_used,
350
        header.timestamp,
351
        header.extra_data,
352
        header.base_fee_per_gas,
353
    )
354
355
    return rlp.rlp_hash(header_data_without_pow_artefacts)

validate_proof_of_work

Validates the Proof of Work constraints.

In order to verify that a miner's proof-of-work is valid for a block, a mix-digest and result are calculated using the hashimoto_light hash function. The mix digest is a hash of the header and the nonce that is passed through and it confirms whether or not proof-of-work was done on the correct block. The result is the actual hash value of the block.

Parameters

header : Header of interest.

def validate_proof_of_work(header: Header) -> None:
359
    """
360
    Validates the Proof of Work constraints.
361
362
    In order to verify that a miner's proof-of-work is valid for a block, a
363
    ``mix-digest`` and ``result`` are calculated using the ``hashimoto_light``
364
    hash function. The mix digest is a hash of the header and the nonce that
365
    is passed through and it confirms whether or not proof-of-work was done
366
    on the correct block. The result is the actual hash value of the block.
367
368
    Parameters
369
    ----------
370
    header :
371
        Header of interest.
372
    """
373
    header_hash = generate_header_hash_for_pow(header)
374
    # TODO: Memoize this somewhere and read from that data instead of
375
    # calculating cache for every block validation.
376
    cache = generate_cache(header.number)
377
    mix_digest, result = hashimoto_light(
378
        header_hash, header.nonce, cache, dataset_size(header.number)
379
    )
380
    if mix_digest != header.mix_digest:
381
        raise InvalidBlock
382
    if Uint.from_be_bytes(result) > (U256_CEIL_VALUE // header.difficulty):
383
        raise InvalidBlock

check_transaction

Check if the transaction is includable in the block.

Parameters

tx : The transaction. base_fee_per_gas : The block base fee. gas_available : The gas remaining in the block. chain_id : The ID of the current chain.

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(tx: Transaction, ​​base_fee_per_gas: Uint, ​​gas_available: Uint, ​​chain_id: U64) -> Tuple[Address, Uint]:
392
    """
393
    Check if the transaction is includable in the block.
394
395
    Parameters
396
    ----------
397
    tx :
398
        The transaction.
399
    base_fee_per_gas :
400
        The block base fee.
401
    gas_available :
402
        The gas remaining in the block.
403
    chain_id :
404
        The ID of the current chain.
405
406
    Returns
407
    -------
408
    sender_address :
409
        The sender of the transaction.
410
    effective_gas_price :
411
        The price to charge for gas when the transaction is executed.
412
413
    Raises
414
    ------
415
    InvalidBlock :
416
        If the transaction is not includable.
417
    """
418
    if tx.gas > gas_available:
419
        raise InvalidBlock
420
    sender_address = recover_sender(chain_id, tx)
421
422
    if isinstance(tx, FeeMarketTransaction):
423
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
424
            raise InvalidBlock
425
        if tx.max_fee_per_gas < base_fee_per_gas:
426
            raise InvalidBlock
427
428
        priority_fee_per_gas = min(
429
            tx.max_priority_fee_per_gas,
430
            tx.max_fee_per_gas - base_fee_per_gas,
431
        )
432
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
433
    else:
434
        if tx.gas_price < base_fee_per_gas:
435
            raise InvalidBlock
436
        effective_gas_price = tx.gas_price
437
438
    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[Exception], ​​cumulative_gas_used: Uint, ​​logs: Tuple[Log, ...]) -> Union[Bytes, Receipt]:
447
    """
448
    Make the receipt for a transaction that was executed.
449
450
    Parameters
451
    ----------
452
    tx :
453
        The executed transaction.
454
    error :
455
        Error in the top level frame of the transaction, if any.
456
    cumulative_gas_used :
457
        The total gas used so far in the block after the transaction was
458
        executed.
459
    logs :
460
        The logs produced by the transaction.
461
462
    Returns
463
    -------
464
    receipt :
465
        The receipt for the transaction.
466
    """
467
    receipt = Receipt(
468
        succeeded=error is None,
469
        cumulative_gas_used=cumulative_gas_used,
470
        bloom=logs_bloom(logs),
471
        logs=logs,
472
    )
473
474
    if isinstance(tx, AccessListTransaction):
475
        return b"\x01" + rlp.encode(receipt)
476
    elif isinstance(tx, FeeMarketTransaction):
477
        return b"\x02" + rlp.encode(receipt)
478
    else:
479
        return receipt

ApplyBodyOutput

Output from applying the block body to the present state.

Contains the following:

block_gas_used : ethereum.base_types.Uint Gas used for executing all transactions. transactions_root : ethereum.fork_types.Root Trie root of all the transactions in the block. receipt_root : ethereum.fork_types.Root Trie root of all the receipts in the block. block_logs_bloom : Bloom Logs bloom of all the logs included in all the transactions of the block. state_root : ethereum.fork_types.Root State root after all transactions have been executed.

482
@dataclass
class ApplyBodyOutput:

block_gas_used

502
    block_gas_used: Uint

transactions_root

503
    transactions_root: Root

receipt_root

504
    receipt_root: Root

block_logs_bloom

505
    block_logs_bloom: Bloom

state_root

506
    state_root: Root

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

state : Current account state. block_hashes : List of hashes of the previous 256 blocks in the order of increasing block number. coinbase : Address of account which receives block reward and transaction fees. block_number : Position of the block within the chain. base_fee_per_gas : Base fee per gas of within the block. block_gas_limit : Initial amount of gas available for execution in this block. block_time : Time the block was produced, measured in seconds since the epoch. block_difficulty : Difficulty of the block. transactions : Transactions included in the block. ommers : Headers of ancestor blocks which are not direct parents (formerly uncles.) chain_id : ID of the executing chain.

Returns

apply_body_output : ApplyBodyOutput Output of applying the block body to the state.

def apply_body(state: State, ​​block_hashes: List[Hash32], ​​coinbase: Address, ​​block_number: Uint, ​​base_fee_per_gas: Uint, ​​block_gas_limit: Uint, ​​block_time: U256, ​​block_difficulty: Uint, ​​transactions: Tuple[Union[LegacyTransaction, Bytes], ...], ​​ommers: Tuple[Header, ...], ​​chain_id: U64) -> ApplyBodyOutput:
522
    """
523
    Executes a block.
524
525
    Many of the contents of a block are stored in data structures called
526
    tries. There is a transactions trie which is similar to a ledger of the
527
    transactions stored in the current block. There is also a receipts trie
528
    which stores the results of executing a transaction, like the post state
529
    and gas used. This function creates and executes the block that is to be
530
    added to the chain.
531
532
    Parameters
533
    ----------
534
    state :
535
        Current account state.
536
    block_hashes :
537
        List of hashes of the previous 256 blocks in the order of
538
        increasing block number.
539
    coinbase :
540
        Address of account which receives block reward and transaction fees.
541
    block_number :
542
        Position of the block within the chain.
543
    base_fee_per_gas :
544
        Base fee per gas of within the block.
545
    block_gas_limit :
546
        Initial amount of gas available for execution in this block.
547
    block_time :
548
        Time the block was produced, measured in seconds since the epoch.
549
    block_difficulty :
550
        Difficulty of the block.
551
    transactions :
552
        Transactions included in the block.
553
    ommers :
554
        Headers of ancestor blocks which are not direct parents (formerly
555
        uncles.)
556
    chain_id :
557
        ID of the executing chain.
558
559
    Returns
560
    -------
561
    apply_body_output : `ApplyBodyOutput`
562
        Output of applying the block body to the state.
563
    """
564
    gas_available = block_gas_limit
565
    transactions_trie: Trie[
566
        Bytes, Optional[Union[Bytes, LegacyTransaction]]
567
    ] = Trie(secured=False, default=None)
568
    receipts_trie: Trie[Bytes, Optional[Union[Bytes, Receipt]]] = Trie(
569
        secured=False, default=None
570
    )
571
    block_logs: Tuple[Log, ...] = ()
572
573
    for i, tx in enumerate(map(decode_transaction, transactions)):
574
        trie_set(
575
            transactions_trie, rlp.encode(Uint(i)), encode_transaction(tx)
576
        )
577
578
        sender_address, effective_gas_price = check_transaction(
579
            tx, base_fee_per_gas, gas_available, chain_id
580
        )
581
582
        env = vm.Environment(
583
            caller=sender_address,
584
            origin=sender_address,
585
            block_hashes=block_hashes,
586
            coinbase=coinbase,
587
            number=block_number,
588
            gas_limit=block_gas_limit,
589
            base_fee_per_gas=base_fee_per_gas,
590
            gas_price=effective_gas_price,
591
            time=block_time,
592
            difficulty=block_difficulty,
593
            state=state,
594
            chain_id=chain_id,
595
            traces=[],
596
        )
597
598
        gas_used, logs, error = process_transaction(env, tx)
599
        gas_available -= gas_used
600
601
        receipt = make_receipt(
602
            tx, error, (block_gas_limit - gas_available), logs
603
        )
604
605
        trie_set(
606
            receipts_trie,
607
            rlp.encode(Uint(i)),
608
            receipt,
609
        )
610
611
        block_logs += logs
612
613
    pay_rewards(state, block_number, coinbase, ommers)
614
615
    block_gas_used = block_gas_limit - gas_available
616
617
    block_logs_bloom = logs_bloom(block_logs)
618
619
    return ApplyBodyOutput(
620
        block_gas_used,
621
        root(transactions_trie),
622
        root(receipts_trie),
623
        block_logs_bloom,
624
        state_root(state),
625
    )

validate_ommers

Validates the ommers mentioned in the block.

An ommer block is a block that wasn't canonically added to the blockchain because it wasn't validated as fast as the canonical block but was mined at the same time.

To be considered valid, the ommers must adhere to the rules defined in the Ethereum protocol. The maximum amount of ommers is 2 per block and there cannot be duplicate ommers in a block. Many of the other ommer constraints are listed in the in-line comments of this function.

Parameters

ommers : List of ommers mentioned in the current block. block_header: The header of current block. chain : History and current state.

def validate_ommers(ommers: Tuple[Header, ...], ​​block_header: Header, ​​chain: BlockChain) -> None:
631
    """
632
    Validates the ommers mentioned in the block.
633
634
    An ommer block is a block that wasn't canonically added to the
635
    blockchain because it wasn't validated as fast as the canonical block
636
    but was mined at the same time.
637
638
    To be considered valid, the ommers must adhere to the rules defined in
639
    the Ethereum protocol. The maximum amount of ommers is 2 per block and
640
    there cannot be duplicate ommers in a block. Many of the other ommer
641
    constraints are listed in the in-line comments of this function.
642
643
    Parameters
644
    ----------
645
    ommers :
646
        List of ommers mentioned in the current block.
647
    block_header:
648
        The header of current block.
649
    chain :
650
        History and current state.
651
    """
652
    block_hash = rlp.rlp_hash(block_header)
653
    if rlp.rlp_hash(ommers) != block_header.ommers_hash:
654
        raise InvalidBlock
655
656
    if len(ommers) == 0:
657
        # Nothing to validate
658
        return
659
660
    # Check that each ommer satisfies the constraints of a header
661
    for ommer in ommers:
662
        if 1 > ommer.number or ommer.number >= block_header.number:
663
            raise InvalidBlock
664
        ommer_parent_header = chain.blocks[
665
            -(block_header.number - ommer.number) - 1
666
        ].header
667
        validate_header(ommer, ommer_parent_header)
668
    if len(ommers) > 2:
669
        raise InvalidBlock
670
671
    ommers_hashes = [rlp.rlp_hash(ommer) for ommer in ommers]
672
    if len(ommers_hashes) != len(set(ommers_hashes)):
673
        raise InvalidBlock
674
675
    recent_canonical_blocks = chain.blocks[-(MAX_OMMER_DEPTH + 1) :]
676
    recent_canonical_block_hashes = {
677
        rlp.rlp_hash(block.header) for block in recent_canonical_blocks
678
    }
679
    recent_ommers_hashes: Set[Hash32] = set()
680
    for block in recent_canonical_blocks:
681
        recent_ommers_hashes = recent_ommers_hashes.union(
682
            {rlp.rlp_hash(ommer) for ommer in block.ommers}
683
        )
684
685
    for ommer_index, ommer in enumerate(ommers):
686
        ommer_hash = ommers_hashes[ommer_index]
687
        if ommer_hash == block_hash:
688
            raise InvalidBlock
689
        if ommer_hash in recent_canonical_block_hashes:
690
            raise InvalidBlock
691
        if ommer_hash in recent_ommers_hashes:
692
            raise InvalidBlock
693
694
        # Ommer age with respect to the current block. For example, an age of
695
        # 1 indicates that the ommer is a sibling of previous block.
696
        ommer_age = block_header.number - ommer.number
697
        if 1 > ommer_age or ommer_age > MAX_OMMER_DEPTH:
698
            raise InvalidBlock
699
        if ommer.parent_hash not in recent_canonical_block_hashes:
700
            raise InvalidBlock
701
        if ommer.parent_hash == block_header.parent_hash:
702
            raise InvalidBlock

pay_rewards

Pay rewards to the block miner as well as the ommers miners.

The miner of the canonical block is rewarded with the predetermined block reward, BLOCK_REWARD, plus a variable award based off of the number of ommer blocks that were mined around the same time, and included in the canonical block's header. An ommer block is a block that wasn't added to the canonical blockchain because it wasn't validated as fast as the accepted block but was mined at the same time. Although not all blocks that are mined are added to the canonical chain, miners are still paid a reward for their efforts. This reward is called an ommer reward and is calculated based on the number associated with the ommer block that they mined.

Parameters

state : Current account state. block_number : Position of the block within the chain. coinbase : Address of account which receives block reward and transaction fees. ommers : List of ommers mentioned in the current block.

def pay_rewards(state: State, ​​block_number: Uint, ​​coinbase: Address, ​​ommers: Tuple[Header, ...]) -> None:
711
    """
712
    Pay rewards to the block miner as well as the ommers miners.
713
714
    The miner of the canonical block is rewarded with the predetermined
715
    block reward, ``BLOCK_REWARD``, plus a variable award based off of the
716
    number of ommer blocks that were mined around the same time, and included
717
    in the canonical block's header. An ommer block is a block that wasn't
718
    added to the canonical blockchain because it wasn't validated as fast as
719
    the accepted block but was mined at the same time. Although not all blocks
720
    that are mined are added to the canonical chain, miners are still paid a
721
    reward for their efforts. This reward is called an ommer reward and is
722
    calculated based on the number associated with the ommer block that they
723
    mined.
724
725
    Parameters
726
    ----------
727
    state :
728
        Current account state.
729
    block_number :
730
        Position of the block within the chain.
731
    coinbase :
732
        Address of account which receives block reward and transaction fees.
733
    ommers :
734
        List of ommers mentioned in the current block.
735
    """
736
    miner_reward = BLOCK_REWARD + (len(ommers) * (BLOCK_REWARD // 32))
737
    create_ether(state, coinbase, miner_reward)
738
739
    for ommer in ommers:
740
        # Ommer age with respect to the current block.
741
        ommer_age = U256(block_number - ommer.number)
742
        ommer_miner_reward = ((8 - ommer_age) * BLOCK_REWARD) // 8
743
        create_ether(state, ommer.coinbase, ommer_miner_reward)

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

env : Environment for the Ethereum Virtual Machine. tx : Transaction to execute.

Returns

gas_left : ethereum.base_types.U256 Remaining gas after execution. logs : Tuple[ethereum.blocks.Log, ...] Logs generated during execution.

def process_transaction(env: ethereum.arrow_glacier.vm.Environment, ​​tx: Transaction) -> Tuple[Uint, Tuple[Log, ...], Optional[Exception]]:
749
    """
750
    Execute a transaction against the provided environment.
751
752
    This function processes the actions needed to execute a transaction.
753
    It decrements the sender's account after calculating the gas fee and
754
    refunds them the proper amount after execution. Calling contracts,
755
    deploying code, and incrementing nonces are all examples of actions that
756
    happen within this function or from a call made within this function.
757
758
    Accounts that are marked for deletion are processed and destroyed after
759
    execution.
760
761
    Parameters
762
    ----------
763
    env :
764
        Environment for the Ethereum Virtual Machine.
765
    tx :
766
        Transaction to execute.
767
768
    Returns
769
    -------
770
    gas_left : `ethereum.base_types.U256`
771
        Remaining gas after execution.
772
    logs : `Tuple[ethereum.blocks.Log, ...]`
773
        Logs generated during execution.
774
    """
775
    if not validate_transaction(tx):
776
        raise InvalidBlock
777
778
    sender = env.origin
779
    sender_account = get_account(env.state, sender)
780
781
    if isinstance(tx, FeeMarketTransaction):
782
        max_gas_fee = tx.gas * tx.max_fee_per_gas
783
    else:
784
        max_gas_fee = tx.gas * tx.gas_price
785
    if sender_account.nonce != tx.nonce:
786
        raise InvalidBlock
787
    if sender_account.balance < max_gas_fee + tx.value:
788
        raise InvalidBlock
789
    if sender_account.code != bytearray():
790
        raise InvalidBlock
791
792
    effective_gas_fee = tx.gas * env.gas_price
793
794
    gas = tx.gas - calculate_intrinsic_cost(tx)
795
    increment_nonce(env.state, sender)
796
797
    sender_balance_after_gas_fee = sender_account.balance - effective_gas_fee
798
    set_account_balance(env.state, sender, sender_balance_after_gas_fee)
799
800
    preaccessed_addresses = set()
801
    preaccessed_storage_keys = set()
802
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
803
        for address, keys in tx.access_list:
804
            preaccessed_addresses.add(address)
805
            for key in keys:
806
                preaccessed_storage_keys.add((address, key))
807
808
    message = prepare_message(
809
        sender,
810
        tx.to,
811
        tx.value,
812
        tx.data,
813
        gas,
814
        env,
815
        preaccessed_addresses=frozenset(preaccessed_addresses),
816
        preaccessed_storage_keys=frozenset(preaccessed_storage_keys),
817
    )
818
819
    output = process_message_call(message, env)
820
821
    gas_used = tx.gas - output.gas_left
822
    gas_refund = min(gas_used // 5, output.refund_counter)
823
    gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price
824
825
    # For non-1559 transactions env.gas_price == tx.gas_price
826
    priority_fee_per_gas = env.gas_price - env.base_fee_per_gas
827
    transaction_fee = (
828
        tx.gas - output.gas_left - gas_refund
829
    ) * priority_fee_per_gas
830
831
    total_gas_used = gas_used - gas_refund
832
833
    # refund gas
834
    sender_balance_after_refund = (
835
        get_account(env.state, sender).balance + gas_refund_amount
836
    )
837
    set_account_balance(env.state, sender, sender_balance_after_refund)
838
839
    # transfer miner fees
840
    coinbase_balance_after_mining_fee = (
841
        get_account(env.state, env.coinbase).balance + transaction_fee
842
    )
843
    if coinbase_balance_after_mining_fee != 0:
844
        set_account_balance(
845
            env.state, env.coinbase, coinbase_balance_after_mining_fee
846
        )
847
    elif account_exists_and_is_empty(env.state, env.coinbase):
848
        destroy_account(env.state, env.coinbase)
849
850
    for address in output.accounts_to_delete:
851
        destroy_account(env.state, address)
852
853
    for address in output.touched_accounts:
854
        if account_exists_and_is_empty(env.state, address):
855
            destroy_account(env.state, address)
856
857
    return total_gas_used, output.logs, output.error

validate_transaction

Verifies a transaction.

The gas in a transaction gets used to pay for the intrinsic cost of operations, therefore if there is insufficient gas then it would not be possible to execute a transaction and it will be declared invalid.

Additionally, the nonce of a transaction must not equal or exceed the limit defined in EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>_. In practice, defining the limit as 2**64-1 has no impact because sending 2**64-1 transactions is improbable. It's not strictly impossible though, 2**64-1 transactions is the entire capacity of the Ethereum blockchain at 2022 gas limits for a little over 22 years.

Parameters

tx : Transaction to validate.

Returns

verified : bool True if the transaction can be executed, or False otherwise.

def validate_transaction(tx: Transaction) -> bool:
861
    """
862
    Verifies a transaction.
863
864
    The gas in a transaction gets used to pay for the intrinsic cost of
865
    operations, therefore if there is insufficient gas then it would not
866
    be possible to execute a transaction and it will be declared invalid.
867
868
    Additionally, the nonce of a transaction must not equal or exceed the
869
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
870
    In practice, defining the limit as ``2**64-1`` has no impact because
871
    sending ``2**64-1`` transactions is improbable. It's not strictly
872
    impossible though, ``2**64-1`` transactions is the entire capacity of the
873
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
874
875
    Parameters
876
    ----------
877
    tx :
878
        Transaction to validate.
879
880
    Returns
881
    -------
882
    verified : `bool`
883
        True if the transaction can be executed, or False otherwise.
884
    """
885
    return calculate_intrinsic_cost(tx) <= tx.gas and tx.nonce < 2**64 - 1

calculate_intrinsic_cost

Calculates the gas that is charged before execution is started.

The intrinsic cost of the transaction is charged before execution has begun. Functions/operations in the EVM cost money to execute so this intrinsic cost is for the operations that need to be paid for as part of the transaction. Data transfer, for example, is part of this intrinsic cost. It costs ether to send data over the wire and that ether is accounted for in the intrinsic cost calculated in this function. This intrinsic cost must be calculated and paid for before execution in order for all operations to be implemented.

Parameters

tx : Transaction to compute the intrinsic cost of.

Returns

verified : ethereum.base_types.Uint The intrinsic cost of the transaction.

def calculate_intrinsic_cost(tx: Transaction) -> Uint:
889
    """
890
    Calculates the gas that is charged before execution is started.
891
892
    The intrinsic cost of the transaction is charged before execution has
893
    begun. Functions/operations in the EVM cost money to execute so this
894
    intrinsic cost is for the operations that need to be paid for as part of
895
    the transaction. Data transfer, for example, is part of this intrinsic
896
    cost. It costs ether to send data over the wire and that ether is
897
    accounted for in the intrinsic cost calculated in this function. This
898
    intrinsic cost must be calculated and paid for before execution in order
899
    for all operations to be implemented.
900
901
    Parameters
902
    ----------
903
    tx :
904
        Transaction to compute the intrinsic cost of.
905
906
    Returns
907
    -------
908
    verified : `ethereum.base_types.Uint`
909
        The intrinsic cost of the transaction.
910
    """
911
    data_cost = 0
912
913
    for byte in tx.data:
914
        if byte == 0:
915
            data_cost += TX_DATA_COST_PER_ZERO
916
        else:
917
            data_cost += TX_DATA_COST_PER_NON_ZERO
918
919
    if tx.to == Bytes0(b""):
920
        create_cost = TX_CREATE_COST
921
    else:
922
        create_cost = 0
923
924
    access_list_cost = 0
925
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
926
        for _address, keys in tx.access_list:
927
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
928
            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
929
930
    return Uint(TX_BASE_COST + data_cost + create_cost + access_list_cost)

recover_sender

Extracts the sender address from a transaction.

The v, r, and s values are the three parts that make up the signature of a transaction. In order to recover the sender of a transaction the two components needed are the signature (v, r, and s) and the signing hash of the transaction. The sender's public key can be obtained with these two values and therefore the sender address can be retrieved.

Parameters

tx : Transaction of interest. chain_id : ID of the executing chain.

Returns

sender : ethereum.fork_types.Address The address of the account that signed the transaction.

def recover_sender(chain_id: U64, ​​tx: Transaction) -> Address:
934
    """
935
    Extracts the sender address from a transaction.
936
937
    The v, r, and s values are the three parts that make up the signature
938
    of a transaction. In order to recover the sender of a transaction the two
939
    components needed are the signature (``v``, ``r``, and ``s``) and the
940
    signing hash of the transaction. The sender's public key can be obtained
941
    with these two values and therefore the sender address can be retrieved.
942
943
    Parameters
944
    ----------
945
    tx :
946
        Transaction of interest.
947
    chain_id :
948
        ID of the executing chain.
949
950
    Returns
951
    -------
952
    sender : `ethereum.fork_types.Address`
953
        The address of the account that signed the transaction.
954
    """
955
    r, s = tx.r, tx.s
956
    if 0 >= r or r >= SECP256K1N:
957
        raise InvalidBlock
958
    if 0 >= s or s > SECP256K1N // 2:
959
        raise InvalidBlock
960
961
    if isinstance(tx, LegacyTransaction):
962
        v = tx.v
963
        if v == 27 or v == 28:
964
            public_key = secp256k1_recover(
965
                r, s, v - 27, signing_hash_pre155(tx)
966
            )
967
        else:
968
            if v != 35 + chain_id * 2 and v != 36 + chain_id * 2:
969
                raise InvalidBlock
970
            public_key = secp256k1_recover(
971
                r, s, v - 35 - chain_id * 2, signing_hash_155(tx, chain_id)
972
            )
973
    elif isinstance(tx, AccessListTransaction):
974
        public_key = secp256k1_recover(
975
            r, s, tx.y_parity, signing_hash_2930(tx)
976
        )
977
    elif isinstance(tx, FeeMarketTransaction):
978
        public_key = secp256k1_recover(
979
            r, s, tx.y_parity, signing_hash_1559(tx)
980
        )
981
982
    return Address(keccak256(public_key)[12:32])

signing_hash_pre155

Compute the hash of a transaction used in a legacy (pre EIP 155) signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_pre155(tx: LegacyTransaction) -> Hash32:
986
    """
987
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
988
989
    Parameters
990
    ----------
991
    tx :
992
        Transaction of interest.
993
994
    Returns
995
    -------
996
    hash : `ethereum.crypto.hash.Hash32`
997
        Hash of the transaction.
998
    """
999
    return keccak256(
1000
        rlp.encode(
1001
            (
1002
                tx.nonce,
1003
                tx.gas_price,
1004
                tx.gas,
1005
                tx.to,
1006
                tx.value,
1007
                tx.data,
1008
            )
1009
        )
1010
    )

signing_hash_155

Compute the hash of a transaction used in a EIP 155 signature.

Parameters

tx : Transaction of interest. chain_id : The id of the current chain.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_155(tx: LegacyTransaction, ​​chain_id: U64) -> Hash32:
1014
    """
1015
    Compute the hash of a transaction used in a EIP 155 signature.
1016
1017
    Parameters
1018
    ----------
1019
    tx :
1020
        Transaction of interest.
1021
    chain_id :
1022
        The id of the current chain.
1023
1024
    Returns
1025
    -------
1026
    hash : `ethereum.crypto.hash.Hash32`
1027
        Hash of the transaction.
1028
    """
1029
    return keccak256(
1030
        rlp.encode(
1031
            (
1032
                tx.nonce,
1033
                tx.gas_price,
1034
                tx.gas,
1035
                tx.to,
1036
                tx.value,
1037
                tx.data,
1038
                chain_id,
1039
                Uint(0),
1040
                Uint(0),
1041
            )
1042
        )
1043
    )

signing_hash_2930

Compute the hash of a transaction used in a EIP 2930 signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_2930(tx: AccessListTransaction) -> Hash32:
1047
    """
1048
    Compute the hash of a transaction used in a EIP 2930 signature.
1049
1050
    Parameters
1051
    ----------
1052
    tx :
1053
        Transaction of interest.
1054
1055
    Returns
1056
    -------
1057
    hash : `ethereum.crypto.hash.Hash32`
1058
        Hash of the transaction.
1059
    """
1060
    return keccak256(
1061
        b"\x01"
1062
        + rlp.encode(
1063
            (
1064
                tx.chain_id,
1065
                tx.nonce,
1066
                tx.gas_price,
1067
                tx.gas,
1068
                tx.to,
1069
                tx.value,
1070
                tx.data,
1071
                tx.access_list,
1072
            )
1073
        )
1074
    )

signing_hash_1559

Compute the hash of a transaction used in a EIP 1559 signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_1559(tx: FeeMarketTransaction) -> Hash32:
1078
    """
1079
    Compute the hash of a transaction used in a EIP 1559 signature.
1080
1081
    Parameters
1082
    ----------
1083
    tx :
1084
        Transaction of interest.
1085
1086
    Returns
1087
    -------
1088
    hash : `ethereum.crypto.hash.Hash32`
1089
        Hash of the transaction.
1090
    """
1091
    return keccak256(
1092
        b"\x02"
1093
        + rlp.encode(
1094
            (
1095
                tx.chain_id,
1096
                tx.nonce,
1097
                tx.max_priority_fee_per_gas,
1098
                tx.max_fee_per_gas,
1099
                tx.gas,
1100
                tx.to,
1101
                tx.value,
1102
                tx.data,
1103
                tx.access_list,
1104
            )
1105
        )
1106
    )

compute_header_hash

Computes the hash of a block header.

The header hash of a block is the canonical hash that is used to refer to a specific block and completely distinguishes a block from another.

keccak256 is a function that produces a 256 bit hash of any input. It also takes in any number of bytes as an input and produces a single hash for them. A hash is a completely unique output for a single input. So an input corresponds to one unique hash that can be used to identify the input exactly.

Prior to using the keccak256 hash function, the header must be encoded using the Recursive-Length Prefix. See :ref:rlp. RLP encoding the header converts it into a space-efficient format that allows for easy transfer of data between nodes. The purpose of RLP is to encode arbitrarily nested arrays of binary data, and RLP is the primary encoding method used to serialize objects in Ethereum's execution layer. The only purpose of RLP is to encode structure; encoding specific data types (e.g. strings, floats) is left up to higher-order protocols.

Parameters

header : Header of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the header.

def compute_header_hash(header: Header) -> Hash32:
1110
    """
1111
    Computes the hash of a block header.
1112
1113
    The header hash of a block is the canonical hash that is used to refer
1114
    to a specific block and completely distinguishes a block from another.
1115
1116
    ``keccak256`` is a function that produces a 256 bit hash of any input.
1117
    It also takes in any number of bytes as an input and produces a single
1118
    hash for them. A hash is a completely unique output for a single input.
1119
    So an input corresponds to one unique hash that can be used to identify
1120
    the input exactly.
1121
1122
    Prior to using the ``keccak256`` hash function, the header must be
1123
    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
1124
    RLP encoding the header converts it into a space-efficient format that
1125
    allows for easy transfer of data between nodes. The purpose of RLP is to
1126
    encode arbitrarily nested arrays of binary data, and RLP is the primary
1127
    encoding method used to serialize objects in Ethereum's execution layer.
1128
    The only purpose of RLP is to encode structure; encoding specific data
1129
    types (e.g. strings, floats) is left up to higher-order protocols.
1130
1131
    Parameters
1132
    ----------
1133
    header :
1134
        Header of interest.
1135
1136
    Returns
1137
    -------
1138
    hash : `ethereum.crypto.hash.Hash32`
1139
        Hash of the header.
1140
    """
1141
    return keccak256(rlp.encode(header))

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:
1145
    """
1146
    Validates the gas limit for a block.
1147
1148
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
1149
    quotient of the parent block's gas limit and the
1150
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
1151
    passed through as a parameter is greater than or equal to the *sum* of
1152
    the parent's gas and the adjustment delta then the limit for gas is too
1153
    high and fails this function's check. Similarly, if the limit is less
1154
    than or equal to the *difference* of the parent's gas and the adjustment
1155
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
1156
    check fails because the gas limit doesn't allow for a sufficient or
1157
    reasonable amount of gas to be used on a block.
1158
1159
    Parameters
1160
    ----------
1161
    gas_limit :
1162
        Gas limit to validate.
1163
1164
    parent_gas_limit :
1165
        Gas limit of the parent block.
1166
1167
    Returns
1168
    -------
1169
    check : `bool`
1170
        True if gas limit constraints are satisfied, False otherwise.
1171
    """
1172
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
1173
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
1174
        return False
1175
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
1176
        return False
1177
    if gas_limit < GAS_LIMIT_MINIMUM:
1178
        return False
1179
1180
    return True

calculate_block_difficulty

Computes difficulty of a block using its header and parent header.

The difficulty is determined by the time the block was created after its parent. The offset is calculated using the parent block's difficulty, parent_difficulty, and the timestamp between blocks. This offset is then added to the parent difficulty and is stored as the difficulty variable. If the time between the block and its parent is too short, the offset will result in a positive number thus making the sum of parent_difficulty and offset to be a greater value in order to avoid mass forking. But, if the time is long enough, then the offset results in a negative value making the block less difficult than its parent.

The base standard for a block's difficulty is the predefined value set for the genesis block since it has no parent. So, a block can't be less difficult than the genesis block, therefore each block's difficulty is set to the maximum value between the calculated difficulty and the GENESIS_DIFFICULTY.

Parameters

block_number : Block number of the block. block_timestamp : Timestamp of the block. parent_timestamp : Timestamp of the parent block. parent_difficulty : difficulty of the parent block. parent_has_ommers: does the parent have ommers.

Returns

difficulty : ethereum.base_types.Uint Computed difficulty for a block.

def calculate_block_difficulty(block_number: Uint, ​​block_timestamp: U256, ​​parent_timestamp: U256, ​​parent_difficulty: Uint, ​​parent_has_ommers: bool) -> Uint:
1190
    """
1191
    Computes difficulty of a block using its header and parent header.
1192
1193
    The difficulty is determined by the time the block was created after its
1194
    parent. The ``offset`` is calculated using the parent block's difficulty,
1195
    ``parent_difficulty``, and the timestamp between blocks. This offset is
1196
    then added to the parent difficulty and is stored as the ``difficulty``
1197
    variable. If the time between the block and its parent is too short, the
1198
    offset will result in a positive number thus making the sum of
1199
    ``parent_difficulty`` and ``offset`` to be a greater value in order to
1200
    avoid mass forking. But, if the time is long enough, then the offset
1201
    results in a negative value making the block less difficult than
1202
    its parent.
1203
1204
    The base standard for a block's difficulty is the predefined value
1205
    set for the genesis block since it has no parent. So, a block
1206
    can't be less difficult than the genesis block, therefore each block's
1207
    difficulty is set to the maximum value between the calculated
1208
    difficulty and the ``GENESIS_DIFFICULTY``.
1209
1210
    Parameters
1211
    ----------
1212
    block_number :
1213
        Block number of the block.
1214
    block_timestamp :
1215
        Timestamp of the block.
1216
    parent_timestamp :
1217
        Timestamp of the parent block.
1218
    parent_difficulty :
1219
        difficulty of the parent block.
1220
    parent_has_ommers:
1221
        does the parent have ommers.
1222
1223
    Returns
1224
    -------
1225
    difficulty : `ethereum.base_types.Uint`
1226
        Computed difficulty for a block.
1227
    """
1228
    offset = (
1229
        int(parent_difficulty)
1230
        // 2048
1231
        * max(
1232
            (2 if parent_has_ommers else 1)
1233
            - int(block_timestamp - parent_timestamp) // 9,
1234
            -99,
1235
        )
1236
    )
1237
    difficulty = int(parent_difficulty) + offset
1238
    # Historical Note: The difficulty bomb was not present in Ethereum at the
1239
    # start of Frontier, but was added shortly after launch. However since the
1240
    # bomb has no effect prior to block 200000 we pretend it existed from
1241
    # genesis.
1242
    # See https://github.com/ethereum/go-ethereum/pull/1588
1243
    num_bomb_periods = ((int(block_number) - BOMB_DELAY_BLOCKS) // 100000) - 2
1244
    if num_bomb_periods >= 0:
1245
        difficulty += 2**num_bomb_periods
1246
1247
    # Some clients raise the difficulty to `MINIMUM_DIFFICULTY` prior to adding
1248
    # the bomb. This bug does not matter because the difficulty is always much
1249
    # greater than `MINIMUM_DIFFICULTY` on Mainnet.
1250
    return Uint(max(difficulty, MINIMUM_DIFFICULTY))