ethereum.arrow_glacier.fork

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

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

Introduction

Entry point for the Ethereum specification.

   1"""
   2Ethereum Specification
   3^^^^^^^^^^^^^^^^^^^^^^
   4
   5.. contents:: Table of Contents
   6    :backlinks: none
   7    :local:
   8
   9Introduction
  10------------
  11
  12Entry point for the Ethereum specification.
  13"""
  14
  15from dataclasses import dataclass
  16from typing import List, Optional, Set, Tuple, Union
  17
  18from ethereum.base_types import Bytes0
  19from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover
  20from ethereum.crypto.hash import Hash32, keccak256
  21from ethereum.ethash import dataset_size, generate_cache, hashimoto_light
  22from ethereum.exceptions import InvalidBlock
  23from ethereum.utils.ensure import ensure
  24
  25from .. import rlp
  26from ..base_types import U64, U256, U256_CEIL_VALUE, Bytes, Uint
  27from . import vm
  28from .bloom import logs_bloom
  29from .fork_types import (
  30    TX_ACCESS_LIST_ADDRESS_COST,
  31    TX_ACCESS_LIST_STORAGE_KEY_COST,
  32    TX_BASE_COST,
  33    TX_CREATE_COST,
  34    TX_DATA_COST_PER_NON_ZERO,
  35    TX_DATA_COST_PER_ZERO,
  36    AccessListTransaction,
  37    Address,
  38    Block,
  39    Bloom,
  40    FeeMarketTransaction,
  41    Header,
  42    LegacyTransaction,
  43    Log,
  44    Receipt,
  45    Root,
  46    Transaction,
  47    decode_transaction,
  48    encode_transaction,
  49)
  50from .state import (
  51    State,
  52    account_exists_and_is_empty,
  53    create_ether,
  54    destroy_account,
  55    get_account,
  56    increment_nonce,
  57    set_account_balance,
  58    state_root,
  59)
  60from .trie import Trie, root, trie_set
  61from .utils.message import prepare_message
  62from .vm.interpreter import process_message_call
  63
  64BLOCK_REWARD = U256(2 * 10**18)
  65BASE_FEE_MAX_CHANGE_DENOMINATOR = 8
  66ELASTICITY_MULTIPLIER = 2
  67GAS_LIMIT_ADJUSTMENT_FACTOR = 1024
  68GAS_LIMIT_MINIMUM = 5000
  69MINIMUM_DIFFICULTY = Uint(131072)
  70MAX_OMMER_DEPTH = 6
  71BOMB_DELAY_BLOCKS = 10700000
  72EMPTY_OMMER_HASH = keccak256(rlp.encode([]))
  73
  74
  75@dataclass
  76class BlockChain:
  77    """
  78    History and current state of the block chain.
  79    """
  80
  81    blocks: List[Block]
  82    state: State
  83    chain_id: U64
  84
  85
  86def apply_fork(old: BlockChain) -> BlockChain:
  87    """
  88    Transforms the state from the previous hard fork (`old`) into the block
  89    chain object for this hard fork and returns it.
  90
  91    When forks need to implement an irregular state transition, this function
  92    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
  93    an example.
  94
  95    Parameters
  96    ----------
  97    old :
  98        Previous block chain object.
  99
 100    Returns
 101    -------
 102    new : `BlockChain`
 103        Upgraded block chain object for this hard fork.
 104    """
 105    return old
 106
 107
 108def get_last_256_block_hashes(chain: BlockChain) -> List[Hash32]:
 109    """
 110    Obtain the list of hashes of the previous 256 blocks in order of
 111    increasing block number.
 112
 113    This function will return less hashes for the first 256 blocks.
 114
 115    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
 116    therefore this function retrieves them.
 117
 118    Parameters
 119    ----------
 120    chain :
 121        History and current state.
 122
 123    Returns
 124    -------
 125    recent_block_hashes : `List[Hash32]`
 126        Hashes of the recent 256 blocks in order of increasing block number.
 127    """
 128    recent_blocks = chain.blocks[-255:]
 129    # TODO: This function has not been tested rigorously
 130    if len(recent_blocks) == 0:
 131        return []
 132
 133    recent_block_hashes = []
 134
 135    for block in recent_blocks:
 136        prev_block_hash = block.header.parent_hash
 137        recent_block_hashes.append(prev_block_hash)
 138
 139    # We are computing the hash only for the most recent block and not for
 140    # the rest of the blocks as they have successors which have the hash of
 141    # the current block as parent hash.
 142    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
 143    recent_block_hashes.append(most_recent_block_hash)
 144
 145    return recent_block_hashes
 146
 147
 148def state_transition(chain: BlockChain, block: Block) -> None:
 149    """
 150    Attempts to apply a block to an existing block chain.
 151
 152    All parts of the block's contents need to be verified before being added
 153    to the chain. Blocks are verified by ensuring that the contents of the
 154    block make logical sense with the contents of the parent block. The
 155    information in the block's header must also match the corresponding
 156    information in the block.
 157
 158    To implement Ethereum, in theory clients are only required to store the
 159    most recent 255 blocks of the chain since as far as execution is
 160    concerned, only those blocks are accessed. Practically, however, clients
 161    should store more blocks to handle reorgs.
 162
 163    Parameters
 164    ----------
 165    chain :
 166        History and current state.
 167    block :
 168        Block to apply to `chain`.
 169    """
 170    parent_header = chain.blocks[-1].header
 171    validate_header(block.header, parent_header)
 172    validate_ommers(block.ommers, block.header, chain)
 173    (
 174        gas_used,
 175        transactions_root,
 176        receipt_root,
 177        block_logs_bloom,
 178        state,
 179    ) = apply_body(
 180        chain.state,
 181        get_last_256_block_hashes(chain),
 182        block.header.coinbase,
 183        block.header.number,
 184        block.header.base_fee_per_gas,
 185        block.header.gas_limit,
 186        block.header.timestamp,
 187        block.header.difficulty,
 188        block.transactions,
 189        block.ommers,
 190        chain.chain_id,
 191    )
 192    ensure(gas_used == block.header.gas_used, InvalidBlock)
 193    ensure(transactions_root == block.header.transactions_root, InvalidBlock)
 194    ensure(state_root(state) == block.header.state_root, InvalidBlock)
 195    ensure(receipt_root == block.header.receipt_root, InvalidBlock)
 196    ensure(block_logs_bloom == block.header.bloom, InvalidBlock)
 197
 198    chain.blocks.append(block)
 199    if len(chain.blocks) > 255:
 200        # Real clients have to store more blocks to deal with reorgs, but the
 201        # protocol only requires the last 255
 202        chain.blocks = chain.blocks[-255:]
 203
 204
 205def calculate_base_fee_per_gas(
 206    block_gas_limit: Uint,
 207    parent_gas_limit: Uint,
 208    parent_gas_used: Uint,
 209    parent_base_fee_per_gas: Uint,
 210) -> Uint:
 211    """
 212    Calculates the base fee per gas for the block.
 213
 214    Parameters
 215    ----------
 216    block_gas_limit :
 217        Gas limit of the block for which the base fee is being calculated.
 218    parent_gas_limit :
 219        Gas limit of the parent block.
 220    parent_gas_used :
 221        Gas used in the parent block.
 222    parent_base_fee_per_gas :
 223        Base fee per gas of the parent block.
 224
 225    Returns
 226    -------
 227    base_fee_per_gas : `Uint`
 228        Base fee per gas for the block.
 229    """
 230    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
 231
 232    ensure(
 233        check_gas_limit(block_gas_limit, parent_gas_limit),
 234        InvalidBlock,
 235    )
 236
 237    if parent_gas_used == parent_gas_target:
 238        expected_base_fee_per_gas = parent_base_fee_per_gas
 239    elif parent_gas_used > parent_gas_target:
 240        gas_used_delta = parent_gas_used - parent_gas_target
 241
 242        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
 243        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
 244
 245        base_fee_per_gas_delta = max(
 246            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
 247            1,
 248        )
 249
 250        expected_base_fee_per_gas = (
 251            parent_base_fee_per_gas + base_fee_per_gas_delta
 252        )
 253    else:
 254        gas_used_delta = parent_gas_target - parent_gas_used
 255
 256        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
 257        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
 258
 259        base_fee_per_gas_delta = (
 260            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
 261        )
 262
 263        expected_base_fee_per_gas = (
 264            parent_base_fee_per_gas - base_fee_per_gas_delta
 265        )
 266
 267    return Uint(expected_base_fee_per_gas)
 268
 269
 270def validate_header(header: Header, parent_header: Header) -> None:
 271    """
 272    Verifies a block header.
 273
 274    In order to consider a block's header valid, the logic for the
 275    quantities in the header should match the logic for the block itself.
 276    For example the header timestamp should be greater than the block's parent
 277    timestamp because the block was created *after* the parent block.
 278    Additionally, the block's number should be directly following the parent
 279    block's number since it is the next block in the sequence.
 280
 281    Parameters
 282    ----------
 283    header :
 284        Header to check for correctness.
 285    parent_header :
 286        Parent Header of the header to check for correctness
 287    """
 288    ensure(header.gas_used <= header.gas_limit, InvalidBlock)
 289
 290    expected_base_fee_per_gas = calculate_base_fee_per_gas(
 291        header.gas_limit,
 292        parent_header.gas_limit,
 293        parent_header.gas_used,
 294        parent_header.base_fee_per_gas,
 295    )
 296
 297    ensure(expected_base_fee_per_gas == header.base_fee_per_gas, InvalidBlock)
 298
 299    parent_has_ommers = parent_header.ommers_hash != EMPTY_OMMER_HASH
 300    ensure(header.timestamp > parent_header.timestamp, InvalidBlock)
 301    ensure(header.number == parent_header.number + 1, InvalidBlock)
 302    ensure(len(header.extra_data) <= 32, InvalidBlock)
 303
 304    block_difficulty = calculate_block_difficulty(
 305        header.number,
 306        header.timestamp,
 307        parent_header.timestamp,
 308        parent_header.difficulty,
 309        parent_has_ommers,
 310    )
 311    ensure(header.difficulty == block_difficulty, InvalidBlock)
 312
 313    block_parent_hash = keccak256(rlp.encode(parent_header))
 314    ensure(header.parent_hash == block_parent_hash, InvalidBlock)
 315
 316    validate_proof_of_work(header)
 317
 318
 319def generate_header_hash_for_pow(header: Header) -> Hash32:
 320    """
 321    Generate rlp hash of the header which is to be used for Proof-of-Work
 322    verification.
 323
 324    In other words, the PoW artefacts `mix_digest` and `nonce` are ignored
 325    while calculating this hash.
 326
 327    A particular PoW is valid for a single hash, that hash is computed by
 328    this function. The `nonce` and `mix_digest` are omitted from this hash
 329    because they are being changed by miners in their search for a sufficient
 330    proof-of-work.
 331
 332    Parameters
 333    ----------
 334    header :
 335        The header object for which the hash is to be generated.
 336
 337    Returns
 338    -------
 339    hash : `Hash32`
 340        The PoW valid rlp hash of the passed in header.
 341    """
 342    header_data_without_pow_artefacts = [
 343        header.parent_hash,
 344        header.ommers_hash,
 345        header.coinbase,
 346        header.state_root,
 347        header.transactions_root,
 348        header.receipt_root,
 349        header.bloom,
 350        header.difficulty,
 351        header.number,
 352        header.gas_limit,
 353        header.gas_used,
 354        header.timestamp,
 355        header.extra_data,
 356        header.base_fee_per_gas,
 357    ]
 358
 359    return rlp.rlp_hash(header_data_without_pow_artefacts)
 360
 361
 362def validate_proof_of_work(header: Header) -> None:
 363    """
 364    Validates the Proof of Work constraints.
 365
 366    In order to verify that a miner's proof-of-work is valid for a block, a
 367    ``mix-digest`` and ``result`` are calculated using the ``hashimoto_light``
 368    hash function. The mix digest is a hash of the header and the nonce that
 369    is passed through and it confirms whether or not proof-of-work was done
 370    on the correct block. The result is the actual hash value of the block.
 371
 372    Parameters
 373    ----------
 374    header :
 375        Header of interest.
 376    """
 377    header_hash = generate_header_hash_for_pow(header)
 378    # TODO: Memoize this somewhere and read from that data instead of
 379    # calculating cache for every block validation.
 380    cache = generate_cache(header.number)
 381    mix_digest, result = hashimoto_light(
 382        header_hash, header.nonce, cache, dataset_size(header.number)
 383    )
 384
 385    ensure(mix_digest == header.mix_digest, InvalidBlock)
 386    ensure(
 387        Uint.from_be_bytes(result) <= (U256_CEIL_VALUE // header.difficulty),
 388        InvalidBlock,
 389    )
 390
 391
 392def check_transaction(
 393    tx: Transaction,
 394    base_fee_per_gas: Uint,
 395    gas_available: Uint,
 396    chain_id: U64,
 397) -> Tuple[Address, Uint]:
 398    """
 399    Check if the transaction is includable in the block.
 400
 401    Parameters
 402    ----------
 403    tx :
 404        The transaction.
 405    base_fee_per_gas :
 406        The block base fee.
 407    gas_available :
 408        The gas remaining in the block.
 409    chain_id :
 410        The ID of the current chain.
 411
 412    Returns
 413    -------
 414    sender_address :
 415        The sender of the transaction.
 416    effective_gas_price :
 417        The price to charge for gas when the transaction is executed.
 418
 419    Raises
 420    ------
 421    InvalidBlock :
 422        If the transaction is not includable.
 423    """
 424    ensure(tx.gas <= gas_available, InvalidBlock)
 425    sender_address = recover_sender(chain_id, tx)
 426
 427    if isinstance(tx, FeeMarketTransaction):
 428        ensure(tx.max_fee_per_gas >= tx.max_priority_fee_per_gas, InvalidBlock)
 429        ensure(tx.max_fee_per_gas >= base_fee_per_gas, InvalidBlock)
 430
 431        priority_fee_per_gas = min(
 432            tx.max_priority_fee_per_gas,
 433            tx.max_fee_per_gas - base_fee_per_gas,
 434        )
 435        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
 436    else:
 437        ensure(tx.gas_price >= base_fee_per_gas, InvalidBlock)
 438        effective_gas_price = tx.gas_price
 439
 440    return sender_address, effective_gas_price
 441
 442
 443def make_receipt(
 444    tx: Transaction,
 445    error: Optional[Exception],
 446    cumulative_gas_used: Uint,
 447    logs: Tuple[Log, ...],
 448) -> Union[Bytes, Receipt]:
 449    """
 450    Make the receipt for a transaction that was executed.
 451
 452    Parameters
 453    ----------
 454    tx :
 455        The executed transaction.
 456    error :
 457        Error in the top level frame of the transaction, if any.
 458    cumulative_gas_used :
 459        The total gas used so far in the block after the transaction was
 460        executed.
 461    logs :
 462        The logs produced by the transaction.
 463
 464    Returns
 465    -------
 466    receipt :
 467        The receipt for the transaction.
 468    """
 469    receipt = Receipt(
 470        succeeded=error is None,
 471        cumulative_gas_used=cumulative_gas_used,
 472        bloom=logs_bloom(logs),
 473        logs=logs,
 474    )
 475
 476    if isinstance(tx, AccessListTransaction):
 477        return b"\x01" + rlp.encode(receipt)
 478    elif isinstance(tx, FeeMarketTransaction):
 479        return b"\x02" + rlp.encode(receipt)
 480    else:
 481        return receipt
 482
 483
 484def apply_body(
 485    state: State,
 486    block_hashes: List[Hash32],
 487    coinbase: Address,
 488    block_number: Uint,
 489    base_fee_per_gas: Uint,
 490    block_gas_limit: Uint,
 491    block_time: U256,
 492    block_difficulty: Uint,
 493    transactions: Tuple[Union[LegacyTransaction, Bytes], ...],
 494    ommers: Tuple[Header, ...],
 495    chain_id: U64,
 496) -> Tuple[Uint, Root, Root, Bloom, State]:
 497    """
 498    Executes a block.
 499
 500    Many of the contents of a block are stored in data structures called
 501    tries. There is a transactions trie which is similar to a ledger of the
 502    transactions stored in the current block. There is also a receipts trie
 503    which stores the results of executing a transaction, like the post state
 504    and gas used. This function creates and executes the block that is to be
 505    added to the chain.
 506
 507    Parameters
 508    ----------
 509    state :
 510        Current account state.
 511    block_hashes :
 512        List of hashes of the previous 256 blocks in the order of
 513        increasing block number.
 514    coinbase :
 515        Address of account which receives block reward and transaction fees.
 516    block_number :
 517        Position of the block within the chain.
 518    base_fee_per_gas :
 519        Base fee per gas of within the block.
 520    block_gas_limit :
 521        Initial amount of gas available for execution in this block.
 522    block_time :
 523        Time the block was produced, measured in seconds since the epoch.
 524    block_difficulty :
 525        Difficulty of the block.
 526    transactions :
 527        Transactions included in the block.
 528    ommers :
 529        Headers of ancestor blocks which are not direct parents (formerly
 530        uncles.)
 531    chain_id :
 532        ID of the executing chain.
 533
 534    Returns
 535    -------
 536    block_gas_used : `ethereum.base_types.Uint`
 537        Gas used for executing all transactions.
 538    transactions_root : `ethereum.fork_types.Root`
 539        Trie root of all the transactions in the block.
 540    receipt_root : `ethereum.fork_types.Root`
 541        Trie root of all the receipts in the block.
 542    block_logs_bloom : `Bloom`
 543        Logs bloom of all the logs included in all the transactions of the
 544        block.
 545    state : `ethereum.fork_types.State`
 546        State after all transactions have been executed.
 547    """
 548    gas_available = block_gas_limit
 549    transactions_trie: Trie[
 550        Bytes, Optional[Union[Bytes, LegacyTransaction]]
 551    ] = Trie(secured=False, default=None)
 552    receipts_trie: Trie[Bytes, Optional[Union[Bytes, Receipt]]] = Trie(
 553        secured=False, default=None
 554    )
 555    block_logs: Tuple[Log, ...] = ()
 556
 557    for i, tx in enumerate(map(decode_transaction, transactions)):
 558        trie_set(
 559            transactions_trie, rlp.encode(Uint(i)), encode_transaction(tx)
 560        )
 561
 562        sender_address, effective_gas_price = check_transaction(
 563            tx, base_fee_per_gas, gas_available, chain_id
 564        )
 565
 566        env = vm.Environment(
 567            caller=sender_address,
 568            origin=sender_address,
 569            block_hashes=block_hashes,
 570            coinbase=coinbase,
 571            number=block_number,
 572            gas_limit=block_gas_limit,
 573            base_fee_per_gas=base_fee_per_gas,
 574            gas_price=effective_gas_price,
 575            time=block_time,
 576            difficulty=block_difficulty,
 577            state=state,
 578            chain_id=chain_id,
 579            traces=[],
 580        )
 581
 582        gas_used, logs, error = process_transaction(env, tx)
 583        gas_available -= gas_used
 584
 585        receipt = make_receipt(
 586            tx, error, (block_gas_limit - gas_available), logs
 587        )
 588
 589        trie_set(
 590            receipts_trie,
 591            rlp.encode(Uint(i)),
 592            receipt,
 593        )
 594
 595        block_logs += logs
 596
 597    pay_rewards(state, block_number, coinbase, ommers)
 598
 599    block_gas_used = block_gas_limit - gas_available
 600
 601    block_logs_bloom = logs_bloom(block_logs)
 602
 603    return (
 604        block_gas_used,
 605        root(transactions_trie),
 606        root(receipts_trie),
 607        block_logs_bloom,
 608        state,
 609    )
 610
 611
 612def validate_ommers(
 613    ommers: Tuple[Header, ...], block_header: Header, chain: BlockChain
 614) -> None:
 615    """
 616    Validates the ommers mentioned in the block.
 617
 618    An ommer block is a block that wasn't canonically added to the
 619    blockchain because it wasn't validated as fast as the canonical block
 620    but was mined at the same time.
 621
 622    To be considered valid, the ommers must adhere to the rules defined in
 623    the Ethereum protocol. The maximum amount of ommers is 2 per block and
 624    there cannot be duplicate ommers in a block. Many of the other ommer
 625    constraints are listed in the in-line comments of this function.
 626
 627    Parameters
 628    ----------
 629    ommers :
 630        List of ommers mentioned in the current block.
 631    block_header:
 632        The header of current block.
 633    chain :
 634        History and current state.
 635    """
 636    block_hash = rlp.rlp_hash(block_header)
 637
 638    ensure(rlp.rlp_hash(ommers) == block_header.ommers_hash, InvalidBlock)
 639
 640    if len(ommers) == 0:
 641        # Nothing to validate
 642        return
 643
 644    # Check that each ommer satisfies the constraints of a header
 645    for ommer in ommers:
 646        ensure(1 <= ommer.number < block_header.number, InvalidBlock)
 647        ommer_parent_header = chain.blocks[
 648            -(block_header.number - ommer.number) - 1
 649        ].header
 650        validate_header(ommer, ommer_parent_header)
 651
 652    # Check that there can be only at most 2 ommers for a block.
 653    ensure(len(ommers) <= 2, InvalidBlock)
 654
 655    ommers_hashes = [rlp.rlp_hash(ommer) for ommer in ommers]
 656    # Check that there are no duplicates in the ommers of current block
 657    ensure(len(ommers_hashes) == len(set(ommers_hashes)), InvalidBlock)
 658
 659    recent_canonical_blocks = chain.blocks[-(MAX_OMMER_DEPTH + 1) :]
 660    recent_canonical_block_hashes = {
 661        rlp.rlp_hash(block.header) for block in recent_canonical_blocks
 662    }
 663    recent_ommers_hashes: Set[Hash32] = set()
 664    for block in recent_canonical_blocks:
 665        recent_ommers_hashes = recent_ommers_hashes.union(
 666            {rlp.rlp_hash(ommer) for ommer in block.ommers}
 667        )
 668
 669    for ommer_index, ommer in enumerate(ommers):
 670        ommer_hash = ommers_hashes[ommer_index]
 671        # The current block shouldn't be the ommer
 672        ensure(ommer_hash != block_hash, InvalidBlock)
 673
 674        # Ommer shouldn't be one of the recent canonical blocks
 675        ensure(ommer_hash not in recent_canonical_block_hashes, InvalidBlock)
 676
 677        # Ommer shouldn't be one of the uncles mentioned in the recent
 678        # canonical blocks
 679        ensure(ommer_hash not in recent_ommers_hashes, InvalidBlock)
 680
 681        # Ommer age with respect to the current block. For example, an age of
 682        # 1 indicates that the ommer is a sibling of previous block.
 683        ommer_age = block_header.number - ommer.number
 684        ensure(1 <= ommer_age <= MAX_OMMER_DEPTH, InvalidBlock)
 685
 686        ensure(
 687            ommer.parent_hash in recent_canonical_block_hashes, InvalidBlock
 688        )
 689        ensure(ommer.parent_hash != block_header.parent_hash, InvalidBlock)
 690
 691
 692def pay_rewards(
 693    state: State,
 694    block_number: Uint,
 695    coinbase: Address,
 696    ommers: Tuple[Header, ...],
 697) -> None:
 698    """
 699    Pay rewards to the block miner as well as the ommers miners.
 700
 701    The miner of the canonical block is rewarded with the predetermined
 702    block reward, ``BLOCK_REWARD``, plus a variable award based off of the
 703    number of ommer blocks that were mined around the same time, and included
 704    in the canonical block's header. An ommer block is a block that wasn't
 705    added to the canonical blockchain because it wasn't validated as fast as
 706    the accepted block but was mined at the same time. Although not all blocks
 707    that are mined are added to the canonical chain, miners are still paid a
 708    reward for their efforts. This reward is called an ommer reward and is
 709    calculated based on the number associated with the ommer block that they
 710    mined.
 711
 712    Parameters
 713    ----------
 714    state :
 715        Current account state.
 716    block_number :
 717        Position of the block within the chain.
 718    coinbase :
 719        Address of account which receives block reward and transaction fees.
 720    ommers :
 721        List of ommers mentioned in the current block.
 722    """
 723    miner_reward = BLOCK_REWARD + (len(ommers) * (BLOCK_REWARD // 32))
 724    create_ether(state, coinbase, miner_reward)
 725
 726    for ommer in ommers:
 727        # Ommer age with respect to the current block.
 728        ommer_age = U256(block_number - ommer.number)
 729        ommer_miner_reward = ((8 - ommer_age) * BLOCK_REWARD) // 8
 730        create_ether(state, ommer.coinbase, ommer_miner_reward)
 731
 732
 733def process_transaction(
 734    env: vm.Environment, tx: Transaction
 735) -> Tuple[Uint, Tuple[Log, ...], Optional[Exception]]:
 736    """
 737    Execute a transaction against the provided environment.
 738
 739    This function processes the actions needed to execute a transaction.
 740    It decrements the sender's account after calculating the gas fee and
 741    refunds them the proper amount after execution. Calling contracts,
 742    deploying code, and incrementing nonces are all examples of actions that
 743    happen within this function or from a call made within this function.
 744
 745    Accounts that are marked for deletion are processed and destroyed after
 746    execution.
 747
 748    Parameters
 749    ----------
 750    env :
 751        Environment for the Ethereum Virtual Machine.
 752    tx :
 753        Transaction to execute.
 754
 755    Returns
 756    -------
 757    gas_left : `ethereum.base_types.U256`
 758        Remaining gas after execution.
 759    logs : `Tuple[ethereum.fork_types.Log, ...]`
 760        Logs generated during execution.
 761    """
 762    ensure(validate_transaction(tx), InvalidBlock)
 763
 764    sender = env.origin
 765    sender_account = get_account(env.state, sender)
 766
 767    if isinstance(tx, FeeMarketTransaction):
 768        max_gas_fee = tx.gas * tx.max_fee_per_gas
 769    else:
 770        max_gas_fee = tx.gas * tx.gas_price
 771
 772    ensure(sender_account.nonce == tx.nonce, InvalidBlock)
 773    ensure(sender_account.balance >= max_gas_fee + tx.value, InvalidBlock)
 774    ensure(sender_account.code == bytearray(), InvalidBlock)
 775
 776    effective_gas_fee = tx.gas * env.gas_price
 777
 778    gas = tx.gas - calculate_intrinsic_cost(tx)
 779    increment_nonce(env.state, sender)
 780
 781    sender_balance_after_gas_fee = sender_account.balance - effective_gas_fee
 782    set_account_balance(env.state, sender, sender_balance_after_gas_fee)
 783
 784    preaccessed_addresses = set()
 785    preaccessed_storage_keys = set()
 786    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
 787        for address, keys in tx.access_list:
 788            preaccessed_addresses.add(address)
 789            for key in keys:
 790                preaccessed_storage_keys.add((address, key))
 791
 792    message = prepare_message(
 793        sender,
 794        tx.to,
 795        tx.value,
 796        tx.data,
 797        gas,
 798        env,
 799        preaccessed_addresses=frozenset(preaccessed_addresses),
 800        preaccessed_storage_keys=frozenset(preaccessed_storage_keys),
 801    )
 802
 803    output = process_message_call(message, env)
 804
 805    gas_used = tx.gas - output.gas_left
 806    gas_refund = min(gas_used // 5, output.refund_counter)
 807    gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price
 808
 809    # For non-1559 transactions env.gas_price == tx.gas_price
 810    priority_fee_per_gas = env.gas_price - env.base_fee_per_gas
 811    transaction_fee = (
 812        tx.gas - output.gas_left - gas_refund
 813    ) * priority_fee_per_gas
 814
 815    total_gas_used = gas_used - gas_refund
 816
 817    # refund gas
 818    sender_balance_after_refund = (
 819        get_account(env.state, sender).balance + gas_refund_amount
 820    )
 821    set_account_balance(env.state, sender, sender_balance_after_refund)
 822
 823    # transfer miner fees
 824    coinbase_balance_after_mining_fee = (
 825        get_account(env.state, env.coinbase).balance + transaction_fee
 826    )
 827    if coinbase_balance_after_mining_fee != 0:
 828        set_account_balance(
 829            env.state, env.coinbase, coinbase_balance_after_mining_fee
 830        )
 831    elif account_exists_and_is_empty(env.state, env.coinbase):
 832        destroy_account(env.state, env.coinbase)
 833
 834    for address in output.accounts_to_delete:
 835        destroy_account(env.state, address)
 836
 837    for address in output.touched_accounts:
 838        if account_exists_and_is_empty(env.state, address):
 839            destroy_account(env.state, address)
 840
 841    return total_gas_used, output.logs, output.error
 842
 843
 844def validate_transaction(tx: Transaction) -> bool:
 845    """
 846    Verifies a transaction.
 847
 848    The gas in a transaction gets used to pay for the intrinsic cost of
 849    operations, therefore if there is insufficient gas then it would not
 850    be possible to execute a transaction and it will be declared invalid.
 851
 852    Additionally, the nonce of a transaction must not equal or exceed the
 853    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
 854    In practice, defining the limit as ``2**64-1`` has no impact because
 855    sending ``2**64-1`` transactions is improbable. It's not strictly
 856    impossible though, ``2**64-1`` transactions is the entire capacity of the
 857    Ethereum blockchain at 2022 gas limits for a little over 22 years.
 858
 859    Parameters
 860    ----------
 861    tx :
 862        Transaction to validate.
 863
 864    Returns
 865    -------
 866    verified : `bool`
 867        True if the transaction can be executed, or False otherwise.
 868    """
 869    return calculate_intrinsic_cost(tx) <= tx.gas and tx.nonce < 2**64 - 1
 870
 871
 872def calculate_intrinsic_cost(tx: Transaction) -> Uint:
 873    """
 874    Calculates the gas that is charged before execution is started.
 875
 876    The intrinsic cost of the transaction is charged before execution has
 877    begun. Functions/operations in the EVM cost money to execute so this
 878    intrinsic cost is for the operations that need to be paid for as part of
 879    the transaction. Data transfer, for example, is part of this intrinsic
 880    cost. It costs ether to send data over the wire and that ether is
 881    accounted for in the intrinsic cost calculated in this function. This
 882    intrinsic cost must be calculated and paid for before execution in order
 883    for all operations to be implemented.
 884
 885    Parameters
 886    ----------
 887    tx :
 888        Transaction to compute the intrinsic cost of.
 889
 890    Returns
 891    -------
 892    verified : `ethereum.base_types.Uint`
 893        The intrinsic cost of the transaction.
 894    """
 895    data_cost = 0
 896
 897    for byte in tx.data:
 898        if byte == 0:
 899            data_cost += TX_DATA_COST_PER_ZERO
 900        else:
 901            data_cost += TX_DATA_COST_PER_NON_ZERO
 902
 903    if tx.to == Bytes0(b""):
 904        create_cost = TX_CREATE_COST
 905    else:
 906        create_cost = 0
 907
 908    access_list_cost = 0
 909    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
 910        for _address, keys in tx.access_list:
 911            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
 912            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
 913
 914    return Uint(TX_BASE_COST + data_cost + create_cost + access_list_cost)
 915
 916
 917def recover_sender(chain_id: U64, tx: Transaction) -> Address:
 918    """
 919    Extracts the sender address from a transaction.
 920
 921    The v, r, and s values are the three parts that make up the signature
 922    of a transaction. In order to recover the sender of a transaction the two
 923    components needed are the signature (``v``, ``r``, and ``s``) and the
 924    signing hash of the transaction. The sender's public key can be obtained
 925    with these two values and therefore the sender address can be retrieved.
 926
 927    Parameters
 928    ----------
 929    tx :
 930        Transaction of interest.
 931    chain_id :
 932        ID of the executing chain.
 933
 934    Returns
 935    -------
 936    sender : `ethereum.fork_types.Address`
 937        The address of the account that signed the transaction.
 938    """
 939    r, s = tx.r, tx.s
 940
 941    ensure(0 < r and r < SECP256K1N, InvalidBlock)
 942    ensure(0 < s and s <= SECP256K1N // 2, InvalidBlock)
 943
 944    if isinstance(tx, LegacyTransaction):
 945        v = tx.v
 946        if v == 27 or v == 28:
 947            public_key = secp256k1_recover(
 948                r, s, v - 27, signing_hash_pre155(tx)
 949            )
 950        else:
 951            ensure(
 952                v == 35 + chain_id * 2 or v == 36 + chain_id * 2, InvalidBlock
 953            )
 954            public_key = secp256k1_recover(
 955                r, s, v - 35 - chain_id * 2, signing_hash_155(tx, chain_id)
 956            )
 957    elif isinstance(tx, AccessListTransaction):
 958        public_key = secp256k1_recover(
 959            r, s, tx.y_parity, signing_hash_2930(tx)
 960        )
 961    elif isinstance(tx, FeeMarketTransaction):
 962        public_key = secp256k1_recover(
 963            r, s, tx.y_parity, signing_hash_1559(tx)
 964        )
 965
 966    return Address(keccak256(public_key)[12:32])
 967
 968
 969def signing_hash_pre155(tx: LegacyTransaction) -> Hash32:
 970    """
 971    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
 972
 973    Parameters
 974    ----------
 975    tx :
 976        Transaction of interest.
 977
 978    Returns
 979    -------
 980    hash : `ethereum.crypto.hash.Hash32`
 981        Hash of the transaction.
 982    """
 983    return keccak256(
 984        rlp.encode(
 985            (
 986                tx.nonce,
 987                tx.gas_price,
 988                tx.gas,
 989                tx.to,
 990                tx.value,
 991                tx.data,
 992            )
 993        )
 994    )
 995
 996
 997def signing_hash_155(tx: LegacyTransaction, chain_id: U64) -> Hash32:
 998    """
 999    Compute the hash of a transaction used in a EIP 155 signature.
1000
1001    Parameters
1002    ----------
1003    tx :
1004        Transaction of interest.
1005    chain_id :
1006        The id of the current chain.
1007
1008    Returns
1009    -------
1010    hash : `ethereum.crypto.hash.Hash32`
1011        Hash of the transaction.
1012    """
1013    return keccak256(
1014        rlp.encode(
1015            (
1016                tx.nonce,
1017                tx.gas_price,
1018                tx.gas,
1019                tx.to,
1020                tx.value,
1021                tx.data,
1022                chain_id,
1023                Uint(0),
1024                Uint(0),
1025            )
1026        )
1027    )
1028
1029
1030def signing_hash_2930(tx: AccessListTransaction) -> Hash32:
1031    """
1032    Compute the hash of a transaction used in a EIP 2930 signature.
1033
1034    Parameters
1035    ----------
1036    tx :
1037        Transaction of interest.
1038
1039    Returns
1040    -------
1041    hash : `ethereum.crypto.hash.Hash32`
1042        Hash of the transaction.
1043    """
1044    return keccak256(
1045        b"\x01"
1046        + rlp.encode(
1047            (
1048                tx.chain_id,
1049                tx.nonce,
1050                tx.gas_price,
1051                tx.gas,
1052                tx.to,
1053                tx.value,
1054                tx.data,
1055                tx.access_list,
1056            )
1057        )
1058    )
1059
1060
1061def signing_hash_1559(tx: FeeMarketTransaction) -> Hash32:
1062    """
1063    Compute the hash of a transaction used in a EIP 1559 signature.
1064
1065    Parameters
1066    ----------
1067    tx :
1068        Transaction of interest.
1069
1070    Returns
1071    -------
1072    hash : `ethereum.crypto.hash.Hash32`
1073        Hash of the transaction.
1074    """
1075    return keccak256(
1076        b"\x02"
1077        + rlp.encode(
1078            (
1079                tx.chain_id,
1080                tx.nonce,
1081                tx.max_priority_fee_per_gas,
1082                tx.max_fee_per_gas,
1083                tx.gas,
1084                tx.to,
1085                tx.value,
1086                tx.data,
1087                tx.access_list,
1088            )
1089        )
1090    )
1091
1092
1093def compute_header_hash(header: Header) -> Hash32:
1094    """
1095    Computes the hash of a block header.
1096
1097    The header hash of a block is the canonical hash that is used to refer
1098    to a specific block and completely distinguishes a block from another.
1099
1100    ``keccak256`` is a function that produces a 256 bit hash of any input.
1101    It also takes in any number of bytes as an input and produces a single
1102    hash for them. A hash is a completely unique output for a single input.
1103    So an input corresponds to one unique hash that can be used to identify
1104    the input exactly.
1105
1106    Prior to using the ``keccak256`` hash function, the header must be
1107    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
1108    RLP encoding the header converts it into a space-efficient format that
1109    allows for easy transfer of data between nodes. The purpose of RLP is to
1110    encode arbitrarily nested arrays of binary data, and RLP is the primary
1111    encoding method used to serialize objects in Ethereum's execution layer.
1112    The only purpose of RLP is to encode structure; encoding specific data
1113    types (e.g. strings, floats) is left up to higher-order protocols.
1114
1115    Parameters
1116    ----------
1117    header :
1118        Header of interest.
1119
1120    Returns
1121    -------
1122    hash : `ethereum.crypto.hash.Hash32`
1123        Hash of the header.
1124    """
1125    return keccak256(rlp.encode(header))
1126
1127
1128def check_gas_limit(gas_limit: Uint, parent_gas_limit: Uint) -> bool:
1129    """
1130    Validates the gas limit for a block.
1131
1132    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
1133    quotient of the parent block's gas limit and the
1134    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
1135    passed through as a parameter is greater than or equal to the *sum* of
1136    the parent's gas and the adjustment delta then the limit for gas is too
1137    high and fails this function's check. Similarly, if the limit is less
1138    than or equal to the *difference* of the parent's gas and the adjustment
1139    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
1140    check fails because the gas limit doesn't allow for a sufficient or
1141    reasonable amount of gas to be used on a block.
1142
1143    Parameters
1144    ----------
1145    gas_limit :
1146        Gas limit to validate.
1147
1148    parent_gas_limit :
1149        Gas limit of the parent block.
1150
1151    Returns
1152    -------
1153    check : `bool`
1154        True if gas limit constraints are satisfied, False otherwise.
1155    """
1156    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
1157    if gas_limit >= parent_gas_limit + max_adjustment_delta:
1158        return False
1159    if gas_limit <= parent_gas_limit - max_adjustment_delta:
1160        return False
1161    if gas_limit < GAS_LIMIT_MINIMUM:
1162        return False
1163
1164    return True
1165
1166
1167def calculate_block_difficulty(
1168    block_number: Uint,
1169    block_timestamp: U256,
1170    parent_timestamp: U256,
1171    parent_difficulty: Uint,
1172    parent_has_ommers: bool,
1173) -> Uint:
1174    """
1175    Computes difficulty of a block using its header and parent header.
1176
1177    The difficulty is determined by the time the block was created after its
1178    parent. The ``offset`` is calculated using the parent block's difficulty,
1179    ``parent_difficulty``, and the timestamp between blocks. This offset is
1180    then added to the parent difficulty and is stored as the ``difficulty``
1181    variable. If the time between the block and its parent is too short, the
1182    offset will result in a positive number thus making the sum of
1183    ``parent_difficulty`` and ``offset`` to be a greater value in order to
1184    avoid mass forking. But, if the time is long enough, then the offset
1185    results in a negative value making the block less difficult than
1186    its parent.
1187
1188    The base standard for a block's difficulty is the predefined value
1189    set for the genesis block since it has no parent. So, a block
1190    can't be less difficult than the genesis block, therefore each block's
1191    difficulty is set to the maximum value between the calculated
1192    difficulty and the ``GENESIS_DIFFICULTY``.
1193
1194    Parameters
1195    ----------
1196    block_number :
1197        Block number of the block.
1198    block_timestamp :
1199        Timestamp of the block.
1200    parent_timestamp :
1201        Timestamp of the parent block.
1202    parent_difficulty :
1203        difficulty of the parent block.
1204    parent_has_ommers:
1205        does the parent have ommers.
1206
1207    Returns
1208    -------
1209    difficulty : `ethereum.base_types.Uint`
1210        Computed difficulty for a block.
1211    """
1212    offset = (
1213        int(parent_difficulty)
1214        // 2048
1215        * max(
1216            (2 if parent_has_ommers else 1)
1217            - int(block_timestamp - parent_timestamp) // 9,
1218            -99,
1219        )
1220    )
1221    difficulty = int(parent_difficulty) + offset
1222    # Historical Note: The difficulty bomb was not present in Ethereum at the
1223    # start of Frontier, but was added shortly after launch. However since the
1224    # bomb has no effect prior to block 200000 we pretend it existed from
1225    # genesis.
1226    # See https://github.com/ethereum/go-ethereum/pull/1588
1227    num_bomb_periods = ((int(block_number) - BOMB_DELAY_BLOCKS) // 100000) - 2
1228    if num_bomb_periods >= 0:
1229        difficulty += 2**num_bomb_periods
1230
1231    # Some clients raise the difficulty to `MINIMUM_DIFFICULTY` prior to adding
1232    # the bomb. This bug does not matter because the difficulty is always much
1233    # greater than `MINIMUM_DIFFICULTY` on Mainnet.
1234    return Uint(max(difficulty, MINIMUM_DIFFICULTY))
@dataclass
class BlockChain:
76@dataclass
77class BlockChain:
78    """
79    History and current state of the block chain.
80    """
81
82    blocks: List[Block]
83    state: State
84    chain_id: U64

History and current state of the block chain.

def apply_fork( old: BlockChain) -> BlockChain:
 87def apply_fork(old: BlockChain) -> BlockChain:
 88    """
 89    Transforms the state from the previous hard fork (`old`) into the block
 90    chain object for this hard fork and returns it.
 91
 92    When forks need to implement an irregular state transition, this function
 93    is used to handle the irregularity. See the :ref:`DAO Fork <dao-fork>` for
 94    an example.
 95
 96    Parameters
 97    ----------
 98    old :
 99        Previous block chain object.
100
101    Returns
102    -------
103    new : `BlockChain`
104        Upgraded block chain object for this hard fork.
105    """
106    return old

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 get_last_256_block_hashes( chain: BlockChain) -> List[ethereum.base_types.Bytes32]:
109def get_last_256_block_hashes(chain: BlockChain) -> List[Hash32]:
110    """
111    Obtain the list of hashes of the previous 256 blocks in order of
112    increasing block number.
113
114    This function will return less hashes for the first 256 blocks.
115
116    The ``BLOCKHASH`` opcode needs to access the latest hashes on the chain,
117    therefore this function retrieves them.
118
119    Parameters
120    ----------
121    chain :
122        History and current state.
123
124    Returns
125    -------
126    recent_block_hashes : `List[Hash32]`
127        Hashes of the recent 256 blocks in order of increasing block number.
128    """
129    recent_blocks = chain.blocks[-255:]
130    # TODO: This function has not been tested rigorously
131    if len(recent_blocks) == 0:
132        return []
133
134    recent_block_hashes = []
135
136    for block in recent_blocks:
137        prev_block_hash = block.header.parent_hash
138        recent_block_hashes.append(prev_block_hash)
139
140    # We are computing the hash only for the most recent block and not for
141    # the rest of the blocks as they have successors which have the hash of
142    # the current block as parent hash.
143    most_recent_block_hash = keccak256(rlp.encode(recent_blocks[-1].header))
144    recent_block_hashes.append(most_recent_block_hash)
145
146    return recent_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 state_transition( chain: BlockChain, block: ethereum.arrow_glacier.fork_types.Block) -> None:
149def state_transition(chain: BlockChain, block: Block) -> None:
150    """
151    Attempts to apply a block to an existing block chain.
152
153    All parts of the block's contents need to be verified before being added
154    to the chain. Blocks are verified by ensuring that the contents of the
155    block make logical sense with the contents of the parent block. The
156    information in the block's header must also match the corresponding
157    information in the block.
158
159    To implement Ethereum, in theory clients are only required to store the
160    most recent 255 blocks of the chain since as far as execution is
161    concerned, only those blocks are accessed. Practically, however, clients
162    should store more blocks to handle reorgs.
163
164    Parameters
165    ----------
166    chain :
167        History and current state.
168    block :
169        Block to apply to `chain`.
170    """
171    parent_header = chain.blocks[-1].header
172    validate_header(block.header, parent_header)
173    validate_ommers(block.ommers, block.header, chain)
174    (
175        gas_used,
176        transactions_root,
177        receipt_root,
178        block_logs_bloom,
179        state,
180    ) = apply_body(
181        chain.state,
182        get_last_256_block_hashes(chain),
183        block.header.coinbase,
184        block.header.number,
185        block.header.base_fee_per_gas,
186        block.header.gas_limit,
187        block.header.timestamp,
188        block.header.difficulty,
189        block.transactions,
190        block.ommers,
191        chain.chain_id,
192    )
193    ensure(gas_used == block.header.gas_used, InvalidBlock)
194    ensure(transactions_root == block.header.transactions_root, InvalidBlock)
195    ensure(state_root(state) == block.header.state_root, InvalidBlock)
196    ensure(receipt_root == block.header.receipt_root, InvalidBlock)
197    ensure(block_logs_bloom == block.header.bloom, InvalidBlock)
198
199    chain.blocks.append(block)
200    if len(chain.blocks) > 255:
201        # Real clients have to store more blocks to deal with reorgs, but the
202        # protocol only requires the last 255
203        chain.blocks = chain.blocks[-255:]

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 calculate_base_fee_per_gas( block_gas_limit: ethereum.base_types.Uint, parent_gas_limit: ethereum.base_types.Uint, parent_gas_used: ethereum.base_types.Uint, parent_base_fee_per_gas: ethereum.base_types.Uint) -> ethereum.base_types.Uint:
206def calculate_base_fee_per_gas(
207    block_gas_limit: Uint,
208    parent_gas_limit: Uint,
209    parent_gas_used: Uint,
210    parent_base_fee_per_gas: Uint,
211) -> Uint:
212    """
213    Calculates the base fee per gas for the block.
214
215    Parameters
216    ----------
217    block_gas_limit :
218        Gas limit of the block for which the base fee is being calculated.
219    parent_gas_limit :
220        Gas limit of the parent block.
221    parent_gas_used :
222        Gas used in the parent block.
223    parent_base_fee_per_gas :
224        Base fee per gas of the parent block.
225
226    Returns
227    -------
228    base_fee_per_gas : `Uint`
229        Base fee per gas for the block.
230    """
231    parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER
232
233    ensure(
234        check_gas_limit(block_gas_limit, parent_gas_limit),
235        InvalidBlock,
236    )
237
238    if parent_gas_used == parent_gas_target:
239        expected_base_fee_per_gas = parent_base_fee_per_gas
240    elif parent_gas_used > parent_gas_target:
241        gas_used_delta = parent_gas_used - parent_gas_target
242
243        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
244        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
245
246        base_fee_per_gas_delta = max(
247            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR,
248            1,
249        )
250
251        expected_base_fee_per_gas = (
252            parent_base_fee_per_gas + base_fee_per_gas_delta
253        )
254    else:
255        gas_used_delta = parent_gas_target - parent_gas_used
256
257        parent_fee_gas_delta = parent_base_fee_per_gas * gas_used_delta
258        target_fee_gas_delta = parent_fee_gas_delta // parent_gas_target
259
260        base_fee_per_gas_delta = (
261            target_fee_gas_delta // BASE_FEE_MAX_CHANGE_DENOMINATOR
262        )
263
264        expected_base_fee_per_gas = (
265            parent_base_fee_per_gas - base_fee_per_gas_delta
266        )
267
268    return Uint(expected_base_fee_per_gas)

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

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 validate_proof_of_work(header: ethereum.arrow_glacier.fork_types.Header) -> None:
363def 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
386    ensure(mix_digest == header.mix_digest, InvalidBlock)
387    ensure(
388        Uint.from_be_bytes(result) <= (U256_CEIL_VALUE // header.difficulty),
389        InvalidBlock,
390    )

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.

393def check_transaction(
394    tx: Transaction,
395    base_fee_per_gas: Uint,
396    gas_available: Uint,
397    chain_id: U64,
398) -> 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    ensure(tx.gas <= gas_available, InvalidBlock)
426    sender_address = recover_sender(chain_id, tx)
427
428    if isinstance(tx, FeeMarketTransaction):
429        ensure(tx.max_fee_per_gas >= tx.max_priority_fee_per_gas, InvalidBlock)
430        ensure(tx.max_fee_per_gas >= base_fee_per_gas, InvalidBlock)
431
432        priority_fee_per_gas = min(
433            tx.max_priority_fee_per_gas,
434            tx.max_fee_per_gas - base_fee_per_gas,
435        )
436        effective_gas_price = priority_fee_per_gas + base_fee_per_gas
437    else:
438        ensure(tx.gas_price >= base_fee_per_gas, InvalidBlock)
439        effective_gas_price = tx.gas_price
440
441    return sender_address, effective_gas_price

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.

444def make_receipt(
445    tx: Transaction,
446    error: Optional[Exception],
447    cumulative_gas_used: Uint,
448    logs: Tuple[Log, ...],
449) -> Union[Bytes, Receipt]:
450    """
451    Make the receipt for a transaction that was executed.
452
453    Parameters
454    ----------
455    tx :
456        The executed transaction.
457    error :
458        Error in the top level frame of the transaction, if any.
459    cumulative_gas_used :
460        The total gas used so far in the block after the transaction was
461        executed.
462    logs :
463        The logs produced by the transaction.
464
465    Returns
466    -------
467    receipt :
468        The receipt for the transaction.
469    """
470    receipt = Receipt(
471        succeeded=error is None,
472        cumulative_gas_used=cumulative_gas_used,
473        bloom=logs_bloom(logs),
474        logs=logs,
475    )
476
477    if isinstance(tx, AccessListTransaction):
478        return b"\x01" + rlp.encode(receipt)
479    elif isinstance(tx, FeeMarketTransaction):
480        return b"\x02" + rlp.encode(receipt)
481    else:
482        return 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.

485def apply_body(
486    state: State,
487    block_hashes: List[Hash32],
488    coinbase: Address,
489    block_number: Uint,
490    base_fee_per_gas: Uint,
491    block_gas_limit: Uint,
492    block_time: U256,
493    block_difficulty: Uint,
494    transactions: Tuple[Union[LegacyTransaction, Bytes], ...],
495    ommers: Tuple[Header, ...],
496    chain_id: U64,
497) -> Tuple[Uint, Root, Root, Bloom, State]:
498    """
499    Executes a block.
500
501    Many of the contents of a block are stored in data structures called
502    tries. There is a transactions trie which is similar to a ledger of the
503    transactions stored in the current block. There is also a receipts trie
504    which stores the results of executing a transaction, like the post state
505    and gas used. This function creates and executes the block that is to be
506    added to the chain.
507
508    Parameters
509    ----------
510    state :
511        Current account state.
512    block_hashes :
513        List of hashes of the previous 256 blocks in the order of
514        increasing block number.
515    coinbase :
516        Address of account which receives block reward and transaction fees.
517    block_number :
518        Position of the block within the chain.
519    base_fee_per_gas :
520        Base fee per gas of within the block.
521    block_gas_limit :
522        Initial amount of gas available for execution in this block.
523    block_time :
524        Time the block was produced, measured in seconds since the epoch.
525    block_difficulty :
526        Difficulty of the block.
527    transactions :
528        Transactions included in the block.
529    ommers :
530        Headers of ancestor blocks which are not direct parents (formerly
531        uncles.)
532    chain_id :
533        ID of the executing chain.
534
535    Returns
536    -------
537    block_gas_used : `ethereum.base_types.Uint`
538        Gas used for executing all transactions.
539    transactions_root : `ethereum.fork_types.Root`
540        Trie root of all the transactions in the block.
541    receipt_root : `ethereum.fork_types.Root`
542        Trie root of all the receipts in the block.
543    block_logs_bloom : `Bloom`
544        Logs bloom of all the logs included in all the transactions of the
545        block.
546    state : `ethereum.fork_types.State`
547        State after all transactions have been executed.
548    """
549    gas_available = block_gas_limit
550    transactions_trie: Trie[
551        Bytes, Optional[Union[Bytes, LegacyTransaction]]
552    ] = Trie(secured=False, default=None)
553    receipts_trie: Trie[Bytes, Optional[Union[Bytes, Receipt]]] = Trie(
554        secured=False, default=None
555    )
556    block_logs: Tuple[Log, ...] = ()
557
558    for i, tx in enumerate(map(decode_transaction, transactions)):
559        trie_set(
560            transactions_trie, rlp.encode(Uint(i)), encode_transaction(tx)
561        )
562
563        sender_address, effective_gas_price = check_transaction(
564            tx, base_fee_per_gas, gas_available, chain_id
565        )
566
567        env = vm.Environment(
568            caller=sender_address,
569            origin=sender_address,
570            block_hashes=block_hashes,
571            coinbase=coinbase,
572            number=block_number,
573            gas_limit=block_gas_limit,
574            base_fee_per_gas=base_fee_per_gas,
575            gas_price=effective_gas_price,
576            time=block_time,
577            difficulty=block_difficulty,
578            state=state,
579            chain_id=chain_id,
580            traces=[],
581        )
582
583        gas_used, logs, error = process_transaction(env, tx)
584        gas_available -= gas_used
585
586        receipt = make_receipt(
587            tx, error, (block_gas_limit - gas_available), logs
588        )
589
590        trie_set(
591            receipts_trie,
592            rlp.encode(Uint(i)),
593            receipt,
594        )
595
596        block_logs += logs
597
598    pay_rewards(state, block_number, coinbase, ommers)
599
600    block_gas_used = block_gas_limit - gas_available
601
602    block_logs_bloom = logs_bloom(block_logs)
603
604    return (
605        block_gas_used,
606        root(transactions_trie),
607        root(receipts_trie),
608        block_logs_bloom,
609        state,
610    )

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

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 : ethereum.fork_types.State State after all transactions have been executed.

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

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 pay_rewards( state: ethereum.arrow_glacier.state.State, block_number: ethereum.base_types.Uint, coinbase: ethereum.base_types.Bytes20, ommers: Tuple[ethereum.arrow_glacier.fork_types.Header, ...]) -> None:
693def pay_rewards(
694    state: State,
695    block_number: Uint,
696    coinbase: Address,
697    ommers: Tuple[Header, ...],
698) -> None:
699    """
700    Pay rewards to the block miner as well as the ommers miners.
701
702    The miner of the canonical block is rewarded with the predetermined
703    block reward, ``BLOCK_REWARD``, plus a variable award based off of the
704    number of ommer blocks that were mined around the same time, and included
705    in the canonical block's header. An ommer block is a block that wasn't
706    added to the canonical blockchain because it wasn't validated as fast as
707    the accepted block but was mined at the same time. Although not all blocks
708    that are mined are added to the canonical chain, miners are still paid a
709    reward for their efforts. This reward is called an ommer reward and is
710    calculated based on the number associated with the ommer block that they
711    mined.
712
713    Parameters
714    ----------
715    state :
716        Current account state.
717    block_number :
718        Position of the block within the chain.
719    coinbase :
720        Address of account which receives block reward and transaction fees.
721    ommers :
722        List of ommers mentioned in the current block.
723    """
724    miner_reward = BLOCK_REWARD + (len(ommers) * (BLOCK_REWARD // 32))
725    create_ether(state, coinbase, miner_reward)
726
727    for ommer in ommers:
728        # Ommer age with respect to the current block.
729        ommer_age = U256(block_number - ommer.number)
730        ommer_miner_reward = ((8 - ommer_age) * BLOCK_REWARD) // 8
731        create_ether(state, ommer.coinbase, ommer_miner_reward)

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.

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

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.fork_types.Log, ...] Logs generated during execution.

845def validate_transaction(tx: Transaction) -> bool:
846    """
847    Verifies a transaction.
848
849    The gas in a transaction gets used to pay for the intrinsic cost of
850    operations, therefore if there is insufficient gas then it would not
851    be possible to execute a transaction and it will be declared invalid.
852
853    Additionally, the nonce of a transaction must not equal or exceed the
854    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
855    In practice, defining the limit as ``2**64-1`` has no impact because
856    sending ``2**64-1`` transactions is improbable. It's not strictly
857    impossible though, ``2**64-1`` transactions is the entire capacity of the
858    Ethereum blockchain at 2022 gas limits for a little over 22 years.
859
860    Parameters
861    ----------
862    tx :
863        Transaction to validate.
864
865    Returns
866    -------
867    verified : `bool`
868        True if the transaction can be executed, or False otherwise.
869    """
870    return calculate_intrinsic_cost(tx) <= tx.gas and tx.nonce < 2**64 - 1

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.

873def calculate_intrinsic_cost(tx: Transaction) -> Uint:
874    """
875    Calculates the gas that is charged before execution is started.
876
877    The intrinsic cost of the transaction is charged before execution has
878    begun. Functions/operations in the EVM cost money to execute so this
879    intrinsic cost is for the operations that need to be paid for as part of
880    the transaction. Data transfer, for example, is part of this intrinsic
881    cost. It costs ether to send data over the wire and that ether is
882    accounted for in the intrinsic cost calculated in this function. This
883    intrinsic cost must be calculated and paid for before execution in order
884    for all operations to be implemented.
885
886    Parameters
887    ----------
888    tx :
889        Transaction to compute the intrinsic cost of.
890
891    Returns
892    -------
893    verified : `ethereum.base_types.Uint`
894        The intrinsic cost of the transaction.
895    """
896    data_cost = 0
897
898    for byte in tx.data:
899        if byte == 0:
900            data_cost += TX_DATA_COST_PER_ZERO
901        else:
902            data_cost += TX_DATA_COST_PER_NON_ZERO
903
904    if tx.to == Bytes0(b""):
905        create_cost = TX_CREATE_COST
906    else:
907        create_cost = 0
908
909    access_list_cost = 0
910    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
911        for _address, keys in tx.access_list:
912            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
913            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
914
915    return Uint(TX_BASE_COST + data_cost + create_cost + access_list_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.

918def recover_sender(chain_id: U64, tx: Transaction) -> Address:
919    """
920    Extracts the sender address from a transaction.
921
922    The v, r, and s values are the three parts that make up the signature
923    of a transaction. In order to recover the sender of a transaction the two
924    components needed are the signature (``v``, ``r``, and ``s``) and the
925    signing hash of the transaction. The sender's public key can be obtained
926    with these two values and therefore the sender address can be retrieved.
927
928    Parameters
929    ----------
930    tx :
931        Transaction of interest.
932    chain_id :
933        ID of the executing chain.
934
935    Returns
936    -------
937    sender : `ethereum.fork_types.Address`
938        The address of the account that signed the transaction.
939    """
940    r, s = tx.r, tx.s
941
942    ensure(0 < r and r < SECP256K1N, InvalidBlock)
943    ensure(0 < s and s <= SECP256K1N // 2, InvalidBlock)
944
945    if isinstance(tx, LegacyTransaction):
946        v = tx.v
947        if v == 27 or v == 28:
948            public_key = secp256k1_recover(
949                r, s, v - 27, signing_hash_pre155(tx)
950            )
951        else:
952            ensure(
953                v == 35 + chain_id * 2 or v == 36 + chain_id * 2, InvalidBlock
954            )
955            public_key = secp256k1_recover(
956                r, s, v - 35 - chain_id * 2, signing_hash_155(tx, chain_id)
957            )
958    elif isinstance(tx, AccessListTransaction):
959        public_key = secp256k1_recover(
960            r, s, tx.y_parity, signing_hash_2930(tx)
961        )
962    elif isinstance(tx, FeeMarketTransaction):
963        public_key = secp256k1_recover(
964            r, s, tx.y_parity, signing_hash_1559(tx)
965        )
966
967    return Address(keccak256(public_key)[12:32])

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.

970def signing_hash_pre155(tx: LegacyTransaction) -> Hash32:
971    """
972    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
973
974    Parameters
975    ----------
976    tx :
977        Transaction of interest.
978
979    Returns
980    -------
981    hash : `ethereum.crypto.hash.Hash32`
982        Hash of the transaction.
983    """
984    return keccak256(
985        rlp.encode(
986            (
987                tx.nonce,
988                tx.gas_price,
989                tx.gas,
990                tx.to,
991                tx.value,
992                tx.data,
993            )
994        )
995    )

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.

 998def signing_hash_155(tx: LegacyTransaction, chain_id: U64) -> Hash32:
 999    """
1000    Compute the hash of a transaction used in a EIP 155 signature.
1001
1002    Parameters
1003    ----------
1004    tx :
1005        Transaction of interest.
1006    chain_id :
1007        The id of the current chain.
1008
1009    Returns
1010    -------
1011    hash : `ethereum.crypto.hash.Hash32`
1012        Hash of the transaction.
1013    """
1014    return keccak256(
1015        rlp.encode(
1016            (
1017                tx.nonce,
1018                tx.gas_price,
1019                tx.gas,
1020                tx.to,
1021                tx.value,
1022                tx.data,
1023                chain_id,
1024                Uint(0),
1025                Uint(0),
1026            )
1027        )
1028    )

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.

1031def signing_hash_2930(tx: AccessListTransaction) -> Hash32:
1032    """
1033    Compute the hash of a transaction used in a EIP 2930 signature.
1034
1035    Parameters
1036    ----------
1037    tx :
1038        Transaction of interest.
1039
1040    Returns
1041    -------
1042    hash : `ethereum.crypto.hash.Hash32`
1043        Hash of the transaction.
1044    """
1045    return keccak256(
1046        b"\x01"
1047        + rlp.encode(
1048            (
1049                tx.chain_id,
1050                tx.nonce,
1051                tx.gas_price,
1052                tx.gas,
1053                tx.to,
1054                tx.value,
1055                tx.data,
1056                tx.access_list,
1057            )
1058        )
1059    )

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.

1062def signing_hash_1559(tx: FeeMarketTransaction) -> Hash32:
1063    """
1064    Compute the hash of a transaction used in a EIP 1559 signature.
1065
1066    Parameters
1067    ----------
1068    tx :
1069        Transaction of interest.
1070
1071    Returns
1072    -------
1073    hash : `ethereum.crypto.hash.Hash32`
1074        Hash of the transaction.
1075    """
1076    return keccak256(
1077        b"\x02"
1078        + rlp.encode(
1079            (
1080                tx.chain_id,
1081                tx.nonce,
1082                tx.max_priority_fee_per_gas,
1083                tx.max_fee_per_gas,
1084                tx.gas,
1085                tx.to,
1086                tx.value,
1087                tx.data,
1088                tx.access_list,
1089            )
1090        )
1091    )

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 compute_header_hash( header: ethereum.arrow_glacier.fork_types.Header) -> ethereum.base_types.Bytes32:
1094def compute_header_hash(header: Header) -> Hash32:
1095    """
1096    Computes the hash of a block header.
1097
1098    The header hash of a block is the canonical hash that is used to refer
1099    to a specific block and completely distinguishes a block from another.
1100
1101    ``keccak256`` is a function that produces a 256 bit hash of any input.
1102    It also takes in any number of bytes as an input and produces a single
1103    hash for them. A hash is a completely unique output for a single input.
1104    So an input corresponds to one unique hash that can be used to identify
1105    the input exactly.
1106
1107    Prior to using the ``keccak256`` hash function, the header must be
1108    encoded using the Recursive-Length Prefix. See :ref:`rlp`.
1109    RLP encoding the header converts it into a space-efficient format that
1110    allows for easy transfer of data between nodes. The purpose of RLP is to
1111    encode arbitrarily nested arrays of binary data, and RLP is the primary
1112    encoding method used to serialize objects in Ethereum's execution layer.
1113    The only purpose of RLP is to encode structure; encoding specific data
1114    types (e.g. strings, floats) is left up to higher-order protocols.
1115
1116    Parameters
1117    ----------
1118    header :
1119        Header of interest.
1120
1121    Returns
1122    -------
1123    hash : `ethereum.crypto.hash.Hash32`
1124        Hash of the header.
1125    """
1126    return keccak256(rlp.encode(header))

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 check_gas_limit( gas_limit: ethereum.base_types.Uint, parent_gas_limit: ethereum.base_types.Uint) -> bool:
1129def check_gas_limit(gas_limit: Uint, parent_gas_limit: Uint) -> bool:
1130    """
1131    Validates the gas limit for a block.
1132
1133    The bounds of the gas limit, ``max_adjustment_delta``, is set as the
1134    quotient of the parent block's gas limit and the
1135    ``GAS_LIMIT_ADJUSTMENT_FACTOR``. Therefore, if the gas limit that is
1136    passed through as a parameter is greater than or equal to the *sum* of
1137    the parent's gas and the adjustment delta then the limit for gas is too
1138    high and fails this function's check. Similarly, if the limit is less
1139    than or equal to the *difference* of the parent's gas and the adjustment
1140    delta *or* the predefined ``GAS_LIMIT_MINIMUM`` then this function's
1141    check fails because the gas limit doesn't allow for a sufficient or
1142    reasonable amount of gas to be used on a block.
1143
1144    Parameters
1145    ----------
1146    gas_limit :
1147        Gas limit to validate.
1148
1149    parent_gas_limit :
1150        Gas limit of the parent block.
1151
1152    Returns
1153    -------
1154    check : `bool`
1155        True if gas limit constraints are satisfied, False otherwise.
1156    """
1157    max_adjustment_delta = parent_gas_limit // GAS_LIMIT_ADJUSTMENT_FACTOR
1158    if gas_limit >= parent_gas_limit + max_adjustment_delta:
1159        return False
1160    if gas_limit <= parent_gas_limit - max_adjustment_delta:
1161        return False
1162    if gas_limit < GAS_LIMIT_MINIMUM:
1163        return False
1164
1165    return True

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