ethereum.london.fork

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

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

Introduction

Entry point for the Ethereum specification.

BLOCK_REWARD

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

BASE_FEE_MAX_CHANGE_DENOMINATOR

56
BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8)

ELASTICITY_MULTIPLIER

57
ELASTICITY_MULTIPLIER = Uint(2)

GAS_LIMIT_ADJUSTMENT_FACTOR

58
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)

GAS_LIMIT_MINIMUM

59
GAS_LIMIT_MINIMUM = Uint(5000)

MINIMUM_DIFFICULTY

60
MINIMUM_DIFFICULTY = Uint(131072)

INITIAL_BASE_FEE

61
INITIAL_BASE_FEE = Uint(1000000000)

MAX_OMMER_DEPTH

62
MAX_OMMER_DEPTH = Uint(6)

BOMB_DELAY_BLOCKS

63
BOMB_DELAY_BLOCKS = 9700000

EMPTY_OMMER_HASH

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

BlockChain

History and current state of the block chain.

67
@dataclass
class BlockChain:

blocks

73
    blocks: List[Block]

state

74
    state: State

chain_id

75
    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:
79
    """
80
    Transforms the state from the previous hard fork (`old`) into the block
81
    chain object for this hard fork and returns it.
82
83
    When forks need to implement an irregular state transition, this function
84
    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
85
    an example.
86
87
    Parameters
88
    ----------
89
    old :
90
        Previous block chain object.
91
92
    Returns
93
    -------
94
    new : `BlockChain`
95
        Upgraded block chain object for this hard fork.
96
    """
97
    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]:
101
    """
102
    Obtain the list of hashes of the previous 256 blocks in order of
103
    increasing block number.
104
105
    This function will return less hashes for the first 256 blocks.
106
107
    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
108
    therefore this function retrieves them.
109
110
    Parameters
111
    ----------
112
    chain :
113
        History and current state.
114
115
    Returns
116
    -------
117
    recent_block_hashes : `List[Hash32]`
118
        Hashes of the recent 256 blocks in order of increasing block number.
119
    """
120
    recent_blocks = chain.blocks[-255:]
121
    # TODO: This function has not been tested rigorously
122
    if len(recent_blocks) == 0:
123
        return []
124
125
    recent_block_hashes = []
126
127
    for block in recent_blocks:
128
        prev_block_hash = block.header.parent_hash
129
        recent_block_hashes.append(prev_block_hash)
130
131
    # We are computing the hash only for the most recent block and not for
132
    # the rest of the blocks as they have successors which have the hash of
133
    # the current block as parent hash.
134
    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
135
    recent_block_hashes.append(most_recent_block_hash)
136
137
    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:
141
    """
142
    Attempts to apply a block to an existing block chain.
143
144
    All parts of the block's contents need to be verified before being added
145
    to the chain. Blocks are verified by ensuring that the contents of the
146
    block make logical sense with the contents of the parent block. The
147
    information in the block's header must also match the corresponding
148
    information in the block.
149
150
    To implement Ethereum, in theory clients are only required to store the
151
    most recent 255 blocks of the chain since as far as execution is
152
    concerned, only those blocks are accessed. Practically, however, clients
153
    should store more blocks to handle reorgs.
154
155
    Parameters
156
    ----------
157
    chain :
158
        History and current state.
159
    block :
160
        Block to apply to `chain`.
161
    """
162
    parent_header = chain.blocks[-1].header
163
    validate_header(block.header, parent_header)
164
    validate_ommers(block.ommers, block.header, chain)
165
    apply_body_output = apply_body(
166
        chain.state,
167
        get_last_256_block_hashes(chain),
168
        block.header.coinbase,
169
        block.header.number,
170
        block.header.base_fee_per_gas,
171
        block.header.gas_limit,
172
        block.header.timestamp,
173
        block.header.difficulty,
174
        block.transactions,
175
        block.ommers,
176
        chain.chain_id,
177
    )
178
    if apply_body_output.block_gas_used != block.header.gas_used:
179
        raise InvalidBlock(
180
            f"{apply_body_output.block_gas_used} != {block.header.gas_used}"
181
        )
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
            Uint(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 = INITIAL_BASE_FEE
282
    if header.number != FORK_CRITERIA.block_number:
283
        # For every block except the first, calculate the base fee per gas
284
        # based on the parent block.
285
        expected_base_fee_per_gas = calculate_base_fee_per_gas(
286
            header.gas_limit,
287
            parent_header.gas_limit,
288
            parent_header.gas_used,
289
            parent_header.base_fee_per_gas,
290
        )
291
292
    if expected_base_fee_per_gas != header.base_fee_per_gas:
293
        raise InvalidBlock
294
295
    parent_has_ommers = parent_header.ommers_hash != EMPTY_OMMER_HASH
296
    if header.timestamp <= parent_header.timestamp:
297
        raise InvalidBlock
298
    if header.number != parent_header.number + Uint(1):
299
        raise InvalidBlock
300
    if len(header.extra_data) > 32:
301
        raise InvalidBlock
302
303
    block_difficulty = calculate_block_difficulty(
304
        header.number,
305
        header.timestamp,
306
        parent_header.timestamp,
307
        parent_header.difficulty,
308
        parent_has_ommers,
309
    )
310
    if header.difficulty != block_difficulty:
311
        raise InvalidBlock
312
313
    block_parent_hash = keccak256(rlp.encode(parent_header))
314
    if header.parent_hash != block_parent_hash:
315
        raise InvalidBlock
316
317
    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:
321
    """
322
    Generate rlp hash of the header which is to be used for Proof-of-Work
323
    verification.
324
325
    In other words, the PoW artefacts `mix_digest` and `nonce` are ignored
326
    while calculating this hash.
327
328
    A particular PoW is valid for a single hash, that hash is computed by
329
    this function. The `nonce` and `mix_digest` are omitted from this hash
330
    because they are being changed by miners in their search for a sufficient
331
    proof-of-work.
332
333
    Parameters
334
    ----------
335
    header :
336
        The header object for which the hash is to be generated.
337
338
    Returns
339
    -------
340
    hash : `Hash32`
341
        The PoW valid rlp hash of the passed in header.
342
    """
343
    header_data_without_pow_artefacts = (
344
        header.parent_hash,
345
        header.ommers_hash,
346
        header.coinbase,
347
        header.state_root,
348
        header.transactions_root,
349
        header.receipt_root,
350
        header.bloom,
351
        header.difficulty,
352
        header.number,
353
        header.gas_limit,
354
        header.gas_used,
355
        header.timestamp,
356
        header.extra_data,
357
        header.base_fee_per_gas,
358
    )
359
360
    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:
364
    """
365
    Validates the Proof of Work constraints.
366
367
    In order to verify that a miner's proof-of-work is valid for a block, a
368
    ``mix-digest`` and ``result`` are calculated using the ``hashimoto_light``
369
    hash function. The mix digest is a hash of the header and the nonce that
370
    is passed through and it confirms whether or not proof-of-work was done
371
    on the correct block. The result is the actual hash value of the block.
372
373
    Parameters
374
    ----------
375
    header :
376
        Header of interest.
377
    """
378
    header_hash = generate_header_hash_for_pow(header)
379
    # TODO: Memoize this somewhere and read from that data instead of
380
    # calculating cache for every block validation.
381
    cache = generate_cache(header.number)
382
    mix_digest, result = hashimoto_light(
383
        header_hash, header.nonce, cache, dataset_size(header.number)
384
    )
385
    if mix_digest != header.mix_digest:
386
        raise InvalidBlock
387
388
    limit = Uint(U256.MAX_VALUE) + Uint(1)
389
    if Uint.from_be_bytes(result) > (limit // header.difficulty):
390
        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]:
399
    """
400
    Check if the transaction is includable in the block.
401
402
    Parameters
403
    ----------
404
    tx :
405
        The transaction.
406
    base_fee_per_gas :
407
        The block base fee.
408
    gas_available :
409
        The gas remaining in the block.
410
    chain_id :
411
        The ID of the current chain.
412
413
    Returns
414
    -------
415
    sender_address :
416
        The sender of the transaction.
417
    effective_gas_price :
418
        The price to charge for gas when the transaction is executed.
419
420
    Raises
421
    ------
422
    InvalidBlock :
423
        If the transaction is not includable.
424
    """
425
    if tx.gas > gas_available:
426
        raise InvalidBlock
427
    sender_address = recover_sender(chain_id, tx)
428
429
    if isinstance(tx, FeeMarketTransaction):
430
        if tx.max_fee_per_gas < tx.max_priority_fee_per_gas:
431
            raise InvalidBlock
432
        if tx.max_fee_per_gas < base_fee_per_gas:
433
            raise InvalidBlock
434
435
        priority_fee_per_gas = min(
436
            tx.max_priority_fee_per_gas,
437
            tx.max_fee_per_gas - base_fee_per_gas,
438
        )
439
        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
440
    else:
441
        if tx.gas_price < base_fee_per_gas:
442
            raise InvalidBlock
443
        effective_gas_price = tx.gas_price
444
445
    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]:
454
    """
455
    Make the receipt for a transaction that was executed.
456
457
    Parameters
458
    ----------
459
    tx :
460
        The executed transaction.
461
    error :
462
        Error in the top level frame of the transaction, if any.
463
    cumulative_gas_used :
464
        The total gas used so far in the block after the transaction was
465
        executed.
466
    logs :
467
        The logs produced by the transaction.
468
469
    Returns
470
    -------
471
    receipt :
472
        The receipt for the transaction.
473
    """
474
    receipt = Receipt(
475
        succeeded=error is None,
476
        cumulative_gas_used=cumulative_gas_used,
477
        bloom=logs_bloom(logs),
478
        logs=logs,
479
    )
480
481
    if isinstance(tx, AccessListTransaction):
482
        return b"\x01" + rlp.encode(receipt)
483
    elif isinstance(tx, FeeMarketTransaction):
484
        return b"\x02" + rlp.encode(receipt)
485
    else:
486
        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.

489
@dataclass
class ApplyBodyOutput:

block_gas_used

509
    block_gas_used: Uint

transactions_root

510
    transactions_root: Root

receipt_root

511
    receipt_root: Root

block_logs_bloom

512
    block_logs_bloom: Bloom

state_root

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

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:
638
    """
639
    Validates the ommers mentioned in the block.
640
641
    An ommer block is a block that wasn't canonically added to the
642
    blockchain because it wasn't validated as fast as the canonical block
643
    but was mined at the same time.
644
645
    To be considered valid, the ommers must adhere to the rules defined in
646
    the Ethereum protocol. The maximum amount of ommers is 2 per block and
647
    there cannot be duplicate ommers in a block. Many of the other ommer
648
    constraints are listed in the in-line comments of this function.
649
650
    Parameters
651
    ----------
652
    ommers :
653
        List of ommers mentioned in the current block.
654
    block_header:
655
        The header of current block.
656
    chain :
657
        History and current state.
658
    """
659
    block_hash = rlp.rlp_hash(block_header)
660
    if rlp.rlp_hash(ommers) != block_header.ommers_hash:
661
        raise InvalidBlock
662
663
    if len(ommers) == 0:
664
        # Nothing to validate
665
        return
666
667
    # Check that each ommer satisfies the constraints of a header
668
    for ommer in ommers:
669
        if Uint(1) > ommer.number or ommer.number >= block_header.number:
670
            raise InvalidBlock
671
        ommer_parent_header = chain.blocks[
672
            -(block_header.number - ommer.number) - 1
673
        ].header
674
        validate_header(ommer, ommer_parent_header)
675
    if len(ommers) > 2:
676
        raise InvalidBlock
677
678
    ommers_hashes = [rlp.rlp_hash(ommer) for ommer in ommers]
679
    if len(ommers_hashes) != len(set(ommers_hashes)):
680
        raise InvalidBlock
681
682
    recent_canonical_blocks = chain.blocks[-(MAX_OMMER_DEPTH + Uint(1)) :]
683
    recent_canonical_block_hashes = {
684
        rlp.rlp_hash(block.header) for block in recent_canonical_blocks
685
    }
686
    recent_ommers_hashes: Set[Hash32] = set()
687
    for block in recent_canonical_blocks:
688
        recent_ommers_hashes = recent_ommers_hashes.union(
689
            {rlp.rlp_hash(ommer) for ommer in block.ommers}
690
        )
691
692
    for ommer_index, ommer in enumerate(ommers):
693
        ommer_hash = ommers_hashes[ommer_index]
694
        if ommer_hash == block_hash:
695
            raise InvalidBlock
696
        if ommer_hash in recent_canonical_block_hashes:
697
            raise InvalidBlock
698
        if ommer_hash in recent_ommers_hashes:
699
            raise InvalidBlock
700
701
        # Ommer age with respect to the current block. For example, an age of
702
        # 1 indicates that the ommer is a sibling of previous block.
703
        ommer_age = block_header.number - ommer.number
704
        if Uint(1) > ommer_age or ommer_age > MAX_OMMER_DEPTH:
705
            raise InvalidBlock
706
        if ommer.parent_hash not in recent_canonical_block_hashes:
707
            raise InvalidBlock
708
        if ommer.parent_hash == block_header.parent_hash:
709
            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:
718
    """
719
    Pay rewards to the block miner as well as the ommers miners.
720
721
    The miner of the canonical block is rewarded with the predetermined
722
    block reward, ``BLOCK_REWARD``, plus a variable award based off of the
723
    number of ommer blocks that were mined around the same time, and included
724
    in the canonical block's header. An ommer block is a block that wasn't
725
    added to the canonical blockchain because it wasn't validated as fast as
726
    the accepted block but was mined at the same time. Although not all blocks
727
    that are mined are added to the canonical chain, miners are still paid a
728
    reward for their efforts. This reward is called an ommer reward and is
729
    calculated based on the number associated with the ommer block that they
730
    mined.
731
732
    Parameters
733
    ----------
734
    state :
735
        Current account state.
736
    block_number :
737
        Position of the block within the chain.
738
    coinbase :
739
        Address of account which receives block reward and transaction fees.
740
    ommers :
741
        List of ommers mentioned in the current block.
742
    """
743
    ommer_count = U256(len(ommers))
744
    miner_reward = BLOCK_REWARD + (ommer_count * (BLOCK_REWARD // U256(32)))
745
    create_ether(state, coinbase, miner_reward)
746
747
    for ommer in ommers:
748
        # Ommer age with respect to the current block.
749
        ommer_age = U256(block_number - ommer.number)
750
        ommer_miner_reward = ((U256(8) - ommer_age) * BLOCK_REWARD) // U256(8)
751
        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.london.vm.Environment, ​​tx: Transaction) -> Tuple[Uint, Tuple[Log, ...], Optional[Exception]]:
757
    """
758
    Execute a transaction against the provided environment.
759
760
    This function processes the actions needed to execute a transaction.
761
    It decrements the sender's account after calculating the gas fee and
762
    refunds them the proper amount after execution. Calling contracts,
763
    deploying code, and incrementing nonces are all examples of actions that
764
    happen within this function or from a call made within this function.
765
766
    Accounts that are marked for deletion are processed and destroyed after
767
    execution.
768
769
    Parameters
770
    ----------
771
    env :
772
        Environment for the Ethereum Virtual Machine.
773
    tx :
774
        Transaction to execute.
775
776
    Returns
777
    -------
778
    gas_left : `ethereum.base_types.U256`
779
        Remaining gas after execution.
780
    logs : `Tuple[ethereum.blocks.Log, ...]`
781
        Logs generated during execution.
782
    """
783
    if not validate_transaction(tx):
784
        raise InvalidBlock
785
786
    sender = env.origin
787
    sender_account = get_account(env.state, sender)
788
789
    max_gas_fee: Uint
790
    if isinstance(tx, FeeMarketTransaction):
791
        max_gas_fee = Uint(tx.gas) * Uint(tx.max_fee_per_gas)
792
    else:
793
        max_gas_fee = Uint(tx.gas) * Uint(tx.gas_price)
794
    if sender_account.nonce != tx.nonce:
795
        raise InvalidBlock
796
    if Uint(sender_account.balance) < max_gas_fee + Uint(tx.value):
797
        raise InvalidBlock
798
    if sender_account.code != bytearray():
799
        raise InvalidSenderError("not EOA")
800
801
    effective_gas_fee = tx.gas * env.gas_price
802
803
    gas = tx.gas - calculate_intrinsic_cost(tx)
804
    increment_nonce(env.state, sender)
805
806
    sender_balance_after_gas_fee = (
807
        Uint(sender_account.balance) - effective_gas_fee
808
    )
809
    set_account_balance(env.state, sender, U256(sender_balance_after_gas_fee))
810
811
    preaccessed_addresses = set()
812
    preaccessed_storage_keys = set()
813
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
814
        for address, keys in tx.access_list:
815
            preaccessed_addresses.add(address)
816
            for key in keys:
817
                preaccessed_storage_keys.add((address, key))
818
819
    message = prepare_message(
820
        sender,
821
        tx.to,
822
        tx.value,
823
        tx.data,
824
        gas,
825
        env,
826
        preaccessed_addresses=frozenset(preaccessed_addresses),
827
        preaccessed_storage_keys=frozenset(preaccessed_storage_keys),
828
    )
829
830
    output = process_message_call(message, env)
831
832
    gas_used = tx.gas - output.gas_left
833
    gas_refund = min(gas_used // Uint(5), Uint(output.refund_counter))
834
    gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price
835
836
    # For non-1559 transactions env.gas_price == tx.gas_price
837
    priority_fee_per_gas = env.gas_price - env.base_fee_per_gas
838
    transaction_fee = (
839
        tx.gas - output.gas_left - gas_refund
840
    ) * priority_fee_per_gas
841
842
    total_gas_used = gas_used - gas_refund
843
844
    # refund gas
845
    sender_balance_after_refund = get_account(
846
        env.state, sender
847
    ).balance + U256(gas_refund_amount)
848
    set_account_balance(env.state, sender, sender_balance_after_refund)
849
850
    # transfer miner fees
851
    coinbase_balance_after_mining_fee = get_account(
852
        env.state, env.coinbase
853
    ).balance + U256(transaction_fee)
854
    if coinbase_balance_after_mining_fee != 0:
855
        set_account_balance(
856
            env.state, env.coinbase, coinbase_balance_after_mining_fee
857
        )
858
    elif account_exists_and_is_empty(env.state, env.coinbase):
859
        destroy_account(env.state, env.coinbase)
860
861
    for address in output.accounts_to_delete:
862
        destroy_account(env.state, address)
863
864
    for address in output.touched_accounts:
865
        if account_exists_and_is_empty(env.state, address):
866
            destroy_account(env.state, address)
867
868
    return total_gas_used, output.logs, output.error

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:
872
    """
873
    Computes the hash of a block header.
874
875
    The header hash of a block is the canonical hash that is used to refer
876
    to a specific block and completely distinguishes a block from another.
877
878
    ``keccak256`` is a function that produces a 256 bit hash of any input.
879
    It also takes in any number of bytes as an input and produces a single
880
    hash for them. A hash is a completely unique output for a single input.
881
    So an input corresponds to one unique hash that can be used to identify
882
    the input exactly.
883
884
    Prior to using the ``keccak256`` hash function, the header must be
885
    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
886
    RLP encoding the header converts it into a space-efficient format that
887
    allows for easy transfer of data between nodes. The purpose of RLP is to
888
    encode arbitrarily nested arrays of binary data, and RLP is the primary
889
    encoding method used to serialize objects in Ethereum's execution layer.
890
    The only purpose of RLP is to encode structure; encoding specific data
891
    types (e.g. strings, floats) is left up to higher-order protocols.
892
893
    Parameters
894
    ----------
895
    header :
896
        Header of interest.
897
898
    Returns
899
    -------
900
    hash : `ethereum.crypto.hash.Hash32`
901
        Hash of the header.
902
    """
903
    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:
907
    """
908
    Validates the gas limit for a block.
909
910
    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
911
    quotient of the parent block's gas limit and the
912
    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
913
    passed through as a parameter is greater than or equal to the *sum* of
914
    the parent's gas and the adjustment delta then the limit for gas is too
915
    high and fails this function's check. Similarly, if the limit is less
916
    than or equal to the *difference* of the parent's gas and the adjustment
917
    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
918
    check fails because the gas limit doesn't allow for a sufficient or
919
    reasonable amount of gas to be used on a block.
920
921
    Parameters
922
    ----------
923
    gas_limit :
924
        Gas limit to validate.
925
926
    parent_gas_limit :
927
        Gas limit of the parent block.
928
929
    Returns
930
    -------
931
    check : `bool`
932
        True if gas limit constraints are satisfied, False otherwise.
933
    """
934
    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
935
    if gas_limit >= parent_gas_limit + max_adjustment_delta:
936
        return False
937
    if gas_limit <= parent_gas_limit - max_adjustment_delta:
938
        return False
939
    if gas_limit < GAS_LIMIT_MINIMUM:
940
        return False
941
942
    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:
952
    """
953
    Computes difficulty of a block using its header and parent header.
954
955
    The difficulty is determined by the time the block was created after its
956
    parent. The ``offset`` is calculated using the parent block's difficulty,
957
    ``parent_difficulty``, and the timestamp between blocks. This offset is
958
    then added to the parent difficulty and is stored as the ``difficulty``
959
    variable. If the time between the block and its parent is too short, the
960
    offset will result in a positive number thus making the sum of
961
    ``parent_difficulty`` and ``offset`` to be a greater value in order to
962
    avoid mass forking. But, if the time is long enough, then the offset
963
    results in a negative value making the block less difficult than
964
    its parent.
965
966
    The base standard for a block's difficulty is the predefined value
967
    set for the genesis block since it has no parent. So, a block
968
    can't be less difficult than the genesis block, therefore each block's
969
    difficulty is set to the maximum value between the calculated
970
    difficulty and the ``GENESIS_DIFFICULTY``.
971
972
    Parameters
973
    ----------
974
    block_number :
975
        Block number of the block.
976
    block_timestamp :
977
        Timestamp of the block.
978
    parent_timestamp :
979
        Timestamp of the parent block.
980
    parent_difficulty :
981
        difficulty of the parent block.
982
    parent_has_ommers:
983
        does the parent have ommers.
984
985
    Returns
986
    -------
987
    difficulty : `ethereum.base_types.Uint`
988
        Computed difficulty for a block.
989
    """
990
    offset = (
991
        int(parent_difficulty)
992
        // 2048
993
        * max(
994
            (2 if parent_has_ommers else 1)
995
            - int(block_timestamp - parent_timestamp) // 9,
996
            -99,
997
        )
998
    )
999
    difficulty = int(parent_difficulty) + offset
1000
    # Historical Note: The difficulty bomb was not present in Ethereum at the
1001
    # start of Frontier, but was added shortly after launch. However since the
1002
    # bomb has no effect prior to block 200000 we pretend it existed from
1003
    # genesis.
1004
    # See https://github.com/ethereum/go-ethereum/pull/1588
1005
    num_bomb_periods = ((int(block_number) - BOMB_DELAY_BLOCKS) // 100000) - 2
1006
    if num_bomb_periods >= 0:
1007
        difficulty += 2**num_bomb_periods
1008
1009
    # Some clients raise the difficulty to `MINIMUM_DIFFICULTY` prior to adding
1010
    # the bomb. This bug does not matter because the difficulty is always much
1011
    # greater than `MINIMUM_DIFFICULTY` on Mainnet.
1012
    return Uint(max(difficulty, int(MINIMUM_DIFFICULTY)))