Skip to content

Ethereum Test Forks package

Ethereum test fork definitions.

ForkAttribute

Bases: Protocol

A protocol to get the attribute of a fork at a given block number and timestamp.

Source code in packages/testing/src/execution_testing/forks/base_fork.py
40
41
42
43
44
45
46
47
48
49
50
class ForkAttribute(Protocol):
    """
    A protocol to get the attribute of a fork at a given block number and
    timestamp.
    """

    def __call__(self, block_number: int = 0, timestamp: int = 0) -> Any:
        """
        Return value of the attribute at the given block number and timestamp.
        """
        pass

__call__(block_number=0, timestamp=0)

Return value of the attribute at the given block number and timestamp.

Source code in packages/testing/src/execution_testing/forks/base_fork.py
46
47
48
49
50
def __call__(self, block_number: int = 0, timestamp: int = 0) -> Any:
    """
    Return value of the attribute at the given block number and timestamp.
    """
    pass

BPO1

Bases: Osaka

Mainnet BPO1 fork - Blob Parameter Only fork 1.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
class BPO1(Osaka, bpo_fork=True):
    """Mainnet BPO1 fork - Blob Parameter Only fork 1."""

    @classmethod
    def blob_base_fee_update_fraction(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the blob base fee update fraction for BPO1."""
        del block_number, timestamp
        return 8346193

    @classmethod
    def target_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in BPO1 have a target of 10 blobs per block."""
        del block_number, timestamp
        return 10

    @classmethod
    def max_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in BPO1 have a max of 15 blobs per block."""
        del block_number, timestamp
        return 15

blob_base_fee_update_fraction(*, block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction for BPO1.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3275
3276
3277
3278
3279
3280
3281
@classmethod
def blob_base_fee_update_fraction(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the blob base fee update fraction for BPO1."""
    del block_number, timestamp
    return 8346193

target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in BPO1 have a target of 10 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3283
3284
3285
3286
3287
3288
3289
@classmethod
def target_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in BPO1 have a target of 10 blobs per block."""
    del block_number, timestamp
    return 10

max_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in BPO1 have a max of 15 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3291
3292
3293
3294
3295
3296
3297
@classmethod
def max_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in BPO1 have a max of 15 blobs per block."""
    del block_number, timestamp
    return 15

BPO2

Bases: BPO1

Mainnet BPO2 fork - Blob Parameter Only fork 2.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
class BPO2(BPO1, bpo_fork=True):
    """Mainnet BPO2 fork - Blob Parameter Only fork 2."""

    @classmethod
    def blob_base_fee_update_fraction(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the blob base fee update fraction for BPO2."""
        del block_number, timestamp
        return 11684671

    @classmethod
    def target_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in BPO2 have a target of 14 blobs per block."""
        del block_number, timestamp
        return 14

    @classmethod
    def max_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in BPO2 have a max of 21 blobs per block."""
        del block_number, timestamp
        return 21

blob_base_fee_update_fraction(*, block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction for BPO2.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3303
3304
3305
3306
3307
3308
3309
@classmethod
def blob_base_fee_update_fraction(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the blob base fee update fraction for BPO2."""
    del block_number, timestamp
    return 11684671

target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in BPO2 have a target of 14 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3311
3312
3313
3314
3315
3316
3317
@classmethod
def target_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in BPO2 have a target of 14 blobs per block."""
    del block_number, timestamp
    return 14

max_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in BPO2 have a max of 21 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3319
3320
3321
3322
3323
3324
3325
@classmethod
def max_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in BPO2 have a max of 21 blobs per block."""
    del block_number, timestamp
    return 21

BPO3

Bases: BPO2

Pseudo BPO3 fork - Blob Parameter Only fork 3. For testing purposes only.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
class BPO3(BPO2, bpo_fork=True):
    """
    Pseudo BPO3 fork - Blob Parameter Only fork 3.
    For testing purposes only.
    """

    @classmethod
    def is_deployed(cls) -> bool:
        """BPO3 is a pseudo fork for testing, not deployed to mainnet."""
        return False

    @classmethod
    def blob_base_fee_update_fraction(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the blob base fee update fraction for BPO3."""
        del block_number, timestamp
        return 20609697

    @classmethod
    def target_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in BPO3 have a target of 21 blobs per block."""
        del block_number, timestamp
        return 21

    @classmethod
    def max_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in BPO3 have a max of 32 blobs per block."""
        del block_number, timestamp
        return 32

is_deployed() classmethod

BPO3 is a pseudo fork for testing, not deployed to mainnet.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3334
3335
3336
3337
@classmethod
def is_deployed(cls) -> bool:
    """BPO3 is a pseudo fork for testing, not deployed to mainnet."""
    return False

blob_base_fee_update_fraction(*, block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction for BPO3.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3339
3340
3341
3342
3343
3344
3345
@classmethod
def blob_base_fee_update_fraction(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the blob base fee update fraction for BPO3."""
    del block_number, timestamp
    return 20609697

target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in BPO3 have a target of 21 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3347
3348
3349
3350
3351
3352
3353
@classmethod
def target_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in BPO3 have a target of 21 blobs per block."""
    del block_number, timestamp
    return 21

max_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in BPO3 have a max of 32 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3355
3356
3357
3358
3359
3360
3361
@classmethod
def max_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in BPO3 have a max of 32 blobs per block."""
    del block_number, timestamp
    return 32

BPO4

Bases: BPO3

Pseudo BPO4 fork - Blob Parameter Only fork 4. For testing purposes only. Testing a decrease in values from BPO3.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
class BPO4(BPO3, bpo_fork=True):
    """
    Pseudo BPO4 fork - Blob Parameter Only fork 4.
    For testing purposes only. Testing a decrease in values from BPO3.
    """

    @classmethod
    def blob_base_fee_update_fraction(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the blob base fee update fraction for BPO4."""
        del block_number, timestamp
        return 13739630

    @classmethod
    def target_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in BPO4 have a target of 14 blobs per block."""
        del block_number, timestamp
        return 14

    @classmethod
    def max_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in BPO4 have a max of 21 blobs per block."""
        del block_number, timestamp
        return 21

blob_base_fee_update_fraction(*, block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction for BPO4.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3370
3371
3372
3373
3374
3375
3376
@classmethod
def blob_base_fee_update_fraction(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the blob base fee update fraction for BPO4."""
    del block_number, timestamp
    return 13739630

target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in BPO4 have a target of 14 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3378
3379
3380
3381
3382
3383
3384
@classmethod
def target_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in BPO4 have a target of 14 blobs per block."""
    del block_number, timestamp
    return 14

max_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in BPO4 have a max of 21 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3386
3387
3388
3389
3390
3391
3392
@classmethod
def max_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in BPO4 have a max of 21 blobs per block."""
    del block_number, timestamp
    return 21

BPO5

Bases: BPO4

Pseudo BPO5 fork - Blob Parameter Only fork 5. For testing purposes only. Required to parse Fusaka devnet genesis files.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3395
3396
3397
3398
3399
3400
3401
class BPO5(BPO4, bpo_fork=True):
    """
    Pseudo BPO5 fork - Blob Parameter Only fork 5.
    For testing purposes only. Required to parse Fusaka devnet genesis files.
    """

    pass

Amsterdam

Bases: BPO2

Amsterdam fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
class Amsterdam(BPO2):
    """Amsterdam fork."""

    # TODO: We may need to adjust which BPO Amsterdam inherits from as the
    #  related Amsterdam specs change over time, and before Amsterdam is
    #  live on mainnet.

    @classmethod
    def header_bal_hash_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """
        From Amsterdam, header must contain block access list hash (EIP-7928).
        """
        del block_number, timestamp
        return True

    @classmethod
    def is_deployed(cls) -> bool:
        """Return True if this fork is deployed."""
        return False

    @classmethod
    def engine_new_payload_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """From Amsterdam, new payload calls must use version 5."""
        del block_number, timestamp
        return 5

    @classmethod
    def engine_execution_payload_block_access_list(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """
        From Amsterdam, engine execution payload includes `block_access_list`
        as a parameter.
        """
        del block_number, timestamp
        return True

header_bal_hash_required(*, block_number=0, timestamp=0) classmethod

From Amsterdam, header must contain block access list hash (EIP-7928).

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3411
3412
3413
3414
3415
3416
3417
3418
3419
@classmethod
def header_bal_hash_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """
    From Amsterdam, header must contain block access list hash (EIP-7928).
    """
    del block_number, timestamp
    return True

is_deployed() classmethod

Return True if this fork is deployed.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3421
3422
3423
3424
@classmethod
def is_deployed(cls) -> bool:
    """Return True if this fork is deployed."""
    return False

engine_new_payload_version(*, block_number=0, timestamp=0) classmethod

From Amsterdam, new payload calls must use version 5.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3426
3427
3428
3429
3430
3431
3432
@classmethod
def engine_new_payload_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """From Amsterdam, new payload calls must use version 5."""
    del block_number, timestamp
    return 5

engine_execution_payload_block_access_list(*, block_number=0, timestamp=0) classmethod

From Amsterdam, engine execution payload includes block_access_list as a parameter.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
@classmethod
def engine_execution_payload_block_access_list(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """
    From Amsterdam, engine execution payload includes `block_access_list`
    as a parameter.
    """
    del block_number, timestamp
    return True

ArrowGlacier

Bases: London

Arrow Glacier fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2150
2151
2152
2153
class ArrowGlacier(London, solc_name="london", ignore=True):
    """Arrow Glacier fork."""

    pass

Berlin

Bases: Istanbul

Berlin fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
class Berlin(Istanbul):
    """Berlin fork."""

    @classmethod
    def tx_types(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[int]:
        """At Berlin, access list transactions are introduced."""
        return [1] + super(Berlin, cls).tx_types(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def contract_creating_tx_types(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[int]:
        """At Berlin, access list transactions are introduced."""
        return [1] + super(Berlin, cls).contract_creating_tx_types(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def transaction_intrinsic_cost_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> TransactionIntrinsicCostCalculator:
        """
        At Berlin, the transaction intrinsic cost needs to take the access list
        into account.
        """
        super_fn = super(Berlin, cls).transaction_intrinsic_cost_calculator(
            block_number=block_number, timestamp=timestamp
        )
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )

        def fn(
            *,
            calldata: BytesConvertible = b"",
            contract_creation: bool = False,
            access_list: List[AccessList] | None = None,
            authorization_list_or_count: Sized | int | None = None,
            return_cost_deducted_prior_execution: bool = False,
        ) -> int:
            del return_cost_deducted_prior_execution

            intrinsic_cost: int = super_fn(
                calldata=calldata,
                contract_creation=contract_creation,
                authorization_list_or_count=authorization_list_or_count,
            )
            if access_list is not None:
                for access in access_list:
                    intrinsic_cost += gas_costs.G_ACCESS_LIST_ADDRESS
                    for _ in access.storage_keys:
                        intrinsic_cost += gas_costs.G_ACCESS_LIST_STORAGE
            return intrinsic_cost

        return fn

tx_types(*, block_number=0, timestamp=0) classmethod

At Berlin, access list transactions are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1872
1873
1874
1875
1876
1877
1878
1879
@classmethod
def tx_types(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[int]:
    """At Berlin, access list transactions are introduced."""
    return [1] + super(Berlin, cls).tx_types(
        block_number=block_number, timestamp=timestamp
    )

contract_creating_tx_types(*, block_number=0, timestamp=0) classmethod

At Berlin, access list transactions are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1881
1882
1883
1884
1885
1886
1887
1888
@classmethod
def contract_creating_tx_types(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[int]:
    """At Berlin, access list transactions are introduced."""
    return [1] + super(Berlin, cls).contract_creating_tx_types(
        block_number=block_number, timestamp=timestamp
    )

transaction_intrinsic_cost_calculator(*, block_number=0, timestamp=0) classmethod

At Berlin, the transaction intrinsic cost needs to take the access list into account.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
@classmethod
def transaction_intrinsic_cost_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> TransactionIntrinsicCostCalculator:
    """
    At Berlin, the transaction intrinsic cost needs to take the access list
    into account.
    """
    super_fn = super(Berlin, cls).transaction_intrinsic_cost_calculator(
        block_number=block_number, timestamp=timestamp
    )
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )

    def fn(
        *,
        calldata: BytesConvertible = b"",
        contract_creation: bool = False,
        access_list: List[AccessList] | None = None,
        authorization_list_or_count: Sized | int | None = None,
        return_cost_deducted_prior_execution: bool = False,
    ) -> int:
        del return_cost_deducted_prior_execution

        intrinsic_cost: int = super_fn(
            calldata=calldata,
            contract_creation=contract_creation,
            authorization_list_or_count=authorization_list_or_count,
        )
        if access_list is not None:
            for access in access_list:
                intrinsic_cost += gas_costs.G_ACCESS_LIST_ADDRESS
                for _ in access.storage_keys:
                    intrinsic_cost += gas_costs.G_ACCESS_LIST_STORAGE
        return intrinsic_cost

    return fn

Byzantium

Bases: SpuriousDragon

Byzantium fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
class Byzantium(SpuriousDragon):
    """Byzantium fork."""

    @classmethod
    def get_reward(cls, *, block_number: int = 0, timestamp: int = 0) -> int:
        """
        At Byzantium, the block reward is reduced to 3_000_000_000_000_000_000
        wei.
        """
        del block_number, timestamp
        return 3_000_000_000_000_000_000

    @classmethod
    def precompiles(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """
        At Byzantium, precompiles for bigint modular exponentiation, addition
        and scalar multiplication on elliptic curve alt_bn128, and optimal ate
        pairing check on elliptic curve alt_bn128 are introduced.
        """
        return [
            Address(5, label="MODEXP"),
            Address(6, label="BN254_ADD"),
            Address(7, label="BN254_MUL"),
            Address(8, label="BN254_PAIRING"),
        ] + super(Byzantium, cls).precompiles(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def max_code_size(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        # NOTE: Move this to Spurious Dragon once this fork is introduced. See
        # EIP-170.
        """
        At Spurious Dragon, an upper bound was introduced for max contract code
        size.
        """
        del block_number, timestamp
        return 0x6000

    @classmethod
    def call_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """At Byzantium, STATICCALL opcode was introduced."""
        return [Opcodes.STATICCALL] + super(Byzantium, cls).call_opcodes(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """Add Byzantium opcodes gas costs."""
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        memory_expansion_calculator = cls.memory_expansion_gas_calculator(
            block_number=block_number, timestamp=timestamp
        )
        base_map = super(Byzantium, cls).opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )
        return {
            **base_map,
            Opcodes.RETURNDATASIZE: gas_costs.G_BASE,
            Opcodes.RETURNDATACOPY: cls._with_memory_expansion(
                cls._with_data_copy(gas_costs.G_VERY_LOW, gas_costs),
                memory_expansion_calculator,
            ),
            Opcodes.STATICCALL: cls._with_memory_expansion(
                lambda op: cls._calculate_call_gas(op, gas_costs),
                memory_expansion_calculator,
            ),
            Opcodes.REVERT: cls._with_memory_expansion(
                0, memory_expansion_calculator
            ),
        }

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [
            Opcodes.REVERT,
            Opcodes.RETURNDATASIZE,
            Opcodes.RETURNDATACOPY,
            Opcodes.STATICCALL,
        ] + super(Byzantium, cls).valid_opcodes()

    @classmethod
    def gas_costs(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> GasCosts:
        """
        On Byzantium, precompiled contract gas costs are introduced.
        """
        return replace(
            super(Byzantium, cls).gas_costs(
                block_number=block_number, timestamp=timestamp
            ),
            G_PRECOMPILE_ECADD=500,
            G_PRECOMPILE_ECMUL=40_000,
            G_PRECOMPILE_ECPAIRING_BASE=100_000,
            G_PRECOMPILE_ECPAIRING_PER_POINT=80_000,
        )

get_reward(*, block_number=0, timestamp=0) classmethod

At Byzantium, the block reward is reduced to 3_000_000_000_000_000_000 wei.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1607
1608
1609
1610
1611
1612
1613
1614
@classmethod
def get_reward(cls, *, block_number: int = 0, timestamp: int = 0) -> int:
    """
    At Byzantium, the block reward is reduced to 3_000_000_000_000_000_000
    wei.
    """
    del block_number, timestamp
    return 3_000_000_000_000_000_000

precompiles(*, block_number=0, timestamp=0) classmethod

At Byzantium, precompiles for bigint modular exponentiation, addition and scalar multiplication on elliptic curve alt_bn128, and optimal ate pairing check on elliptic curve alt_bn128 are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
@classmethod
def precompiles(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """
    At Byzantium, precompiles for bigint modular exponentiation, addition
    and scalar multiplication on elliptic curve alt_bn128, and optimal ate
    pairing check on elliptic curve alt_bn128 are introduced.
    """
    return [
        Address(5, label="MODEXP"),
        Address(6, label="BN254_ADD"),
        Address(7, label="BN254_MUL"),
        Address(8, label="BN254_PAIRING"),
    ] + super(Byzantium, cls).precompiles(
        block_number=block_number, timestamp=timestamp
    )

max_code_size(*, block_number=0, timestamp=0) classmethod

At Spurious Dragon, an upper bound was introduced for max contract code size.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
@classmethod
def max_code_size(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    # NOTE: Move this to Spurious Dragon once this fork is introduced. See
    # EIP-170.
    """
    At Spurious Dragon, an upper bound was introduced for max contract code
    size.
    """
    del block_number, timestamp
    return 0x6000

call_opcodes(*, block_number=0, timestamp=0) classmethod

At Byzantium, STATICCALL opcode was introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1647
1648
1649
1650
1651
1652
1653
1654
@classmethod
def call_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """At Byzantium, STATICCALL opcode was introduced."""
    return [Opcodes.STATICCALL] + super(Byzantium, cls).call_opcodes(
        block_number=block_number, timestamp=timestamp
    )

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Add Byzantium opcodes gas costs.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """Add Byzantium opcodes gas costs."""
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    memory_expansion_calculator = cls.memory_expansion_gas_calculator(
        block_number=block_number, timestamp=timestamp
    )
    base_map = super(Byzantium, cls).opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )
    return {
        **base_map,
        Opcodes.RETURNDATASIZE: gas_costs.G_BASE,
        Opcodes.RETURNDATACOPY: cls._with_memory_expansion(
            cls._with_data_copy(gas_costs.G_VERY_LOW, gas_costs),
            memory_expansion_calculator,
        ),
        Opcodes.STATICCALL: cls._with_memory_expansion(
            lambda op: cls._calculate_call_gas(op, gas_costs),
            memory_expansion_calculator,
        ),
        Opcodes.REVERT: cls._with_memory_expansion(
            0, memory_expansion_calculator
        ),
    }

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [
        Opcodes.REVERT,
        Opcodes.RETURNDATASIZE,
        Opcodes.RETURNDATACOPY,
        Opcodes.STATICCALL,
    ] + super(Byzantium, cls).valid_opcodes()

gas_costs(*, block_number=0, timestamp=0) classmethod

On Byzantium, precompiled contract gas costs are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
@classmethod
def gas_costs(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> GasCosts:
    """
    On Byzantium, precompiled contract gas costs are introduced.
    """
    return replace(
        super(Byzantium, cls).gas_costs(
            block_number=block_number, timestamp=timestamp
        ),
        G_PRECOMPILE_ECADD=500,
        G_PRECOMPILE_ECMUL=40_000,
        G_PRECOMPILE_ECPAIRING_BASE=100_000,
        G_PRECOMPILE_ECPAIRING_PER_POINT=80_000,
    )

Cancun

Bases: Shanghai

Cancun fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
class Cancun(Shanghai):
    """Cancun fork."""

    BLOB_CONSTANTS = {  # every value is an int or a Literal
        "FIELD_ELEMENTS_PER_BLOB": 4096,
        "BYTES_PER_FIELD_ELEMENT": 32,
        "CELL_LENGTH": 2048,
        # EIP-2537: Main subgroup order = q, due to this BLS_MODULUS
        # every blob byte (uint256) must be smaller than 116
        "BLS_MODULUS": (
            0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001
        ),
        # https://github.com/ethereum/consensus-specs/blob/
        # cc6996c22692d70e41b7a453d925172ee4b719ad/specs/deneb/
        # polynomial-commitments.md?plain=1#L78
        "BYTES_PER_PROOF": 48,
        "BYTES_PER_COMMITMENT": 48,
        "KZG_ENDIANNESS": "big",
        "AMOUNT_CELL_PROOFS": 0,
    }

    @classmethod
    def get_blob_constant(cls, name: str) -> int | Literal["big"]:
        """Return blob constant if it exists."""
        retrieved_constant = cls.BLOB_CONSTANTS.get(name)
        assert retrieved_constant is not None, (
            f"You tried to retrieve the blob constant {name} but it does "
            "not exist!"
        )
        return retrieved_constant

    @classmethod
    def header_excess_blob_gas_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Excess blob gas is required starting from Cancun."""
        del block_number, timestamp
        return True

    @classmethod
    def header_blob_gas_used_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Blob gas used is required starting from Cancun."""
        del block_number, timestamp
        return True

    @classmethod
    def header_beacon_root_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Parent beacon block root is required starting from Cancun."""
        del block_number, timestamp
        return True

    @classmethod
    def blob_gas_price_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> BlobGasPriceCalculator:
        """Return a callable that calculates the blob gas price at Cancun."""
        min_base_fee_per_blob_gas = cls.min_base_fee_per_blob_gas(
            block_number=block_number, timestamp=timestamp
        )
        blob_base_fee_update_fraction = cls.blob_base_fee_update_fraction(
            block_number=block_number, timestamp=timestamp
        )

        def fn(*, excess_blob_gas: int) -> int:
            return fake_exponential(
                min_base_fee_per_blob_gas,
                excess_blob_gas,
                blob_base_fee_update_fraction,
            )

        return fn

    @classmethod
    def excess_blob_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> ExcessBlobGasCalculator:
        """
        Return a callable that calculates the excess blob gas for a block at
        Cancun.
        """
        target_blobs_per_block = cls.target_blobs_per_block(
            block_number=block_number, timestamp=timestamp
        )
        blob_gas_per_blob = cls.blob_gas_per_blob(
            block_number=block_number, timestamp=timestamp
        )
        target_blob_gas_per_block = target_blobs_per_block * blob_gas_per_blob

        def fn(
            *,
            parent_excess_blob_gas: int | None = None,
            parent_excess_blobs: int | None = None,
            parent_blob_gas_used: int | None = None,
            parent_blob_count: int | None = None,
            # Required for Osaka as using this as base
            parent_base_fee_per_gas: int,
        ) -> int:
            del parent_base_fee_per_gas

            if parent_excess_blob_gas is None:
                assert parent_excess_blobs is not None, (
                    "Parent excess blobs are required"
                )
                parent_excess_blob_gas = (
                    parent_excess_blobs * blob_gas_per_blob
                )
            if parent_blob_gas_used is None:
                assert parent_blob_count is not None, (
                    "Parent blob count is required"
                )
                parent_blob_gas_used = parent_blob_count * blob_gas_per_blob
            if (
                parent_excess_blob_gas + parent_blob_gas_used
                < target_blob_gas_per_block
            ):
                return 0
            else:
                return (
                    parent_excess_blob_gas
                    + parent_blob_gas_used
                    - target_blob_gas_per_block
                )

        return fn

    @classmethod
    def min_base_fee_per_blob_gas(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the minimum base fee per blob gas for Cancun."""
        del block_number, timestamp
        return 1

    @classmethod
    def blob_base_fee_update_fraction(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the blob base fee update fraction for Cancun."""
        del block_number, timestamp
        return 3338477

    @classmethod
    def blob_gas_per_blob(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs are enabled starting from Cancun."""
        del block_number, timestamp
        return 2**17

    @classmethod
    def supports_blobs(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At Cancun, blobs support is enabled."""
        del block_number, timestamp
        return True

    @classmethod
    def target_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """
        Blobs are enabled starting from Cancun, with a static target of 3 blobs
        per block.
        """
        del block_number, timestamp
        return 3

    @classmethod
    def max_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """
        Blobs are enabled starting from Cancun, with a static max of 6 blobs
        per block.
        """
        del block_number, timestamp
        return 6

    @classmethod
    def blob_reserve_price_active(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Blob reserve price is not supported in Cancun."""
        del block_number, timestamp
        return False

    @classmethod
    def full_blob_tx_wrapper_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int | None:
        """
        Pre-Osaka forks don't use tx wrapper versions for full blob
        transactions.
        """
        del block_number, timestamp
        return None

    @classmethod
    def max_blobs_per_tx(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """
        Blobs are enabled starting from Cancun, with a static max equal to the
        max per block.
        """
        return cls.max_blobs_per_block(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def blob_schedule(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> BlobSchedule | None:
        """
        At Cancun, the fork object runs this routine to get the updated blob
        schedule.
        """
        parent_fork = cls.parent()
        assert parent_fork is not None, "Parent fork must be defined"
        blob_schedule = (
            parent_fork.blob_schedule(
                block_number=block_number, timestamp=timestamp
            )
            or BlobSchedule()
        )
        current_blob_schedule = ForkBlobSchedule(
            target_blobs_per_block=cls.target_blobs_per_block(
                block_number=block_number, timestamp=timestamp
            ),
            max_blobs_per_block=cls.max_blobs_per_block(
                block_number=block_number, timestamp=timestamp
            ),
            base_fee_update_fraction=cls.blob_base_fee_update_fraction(
                block_number=block_number, timestamp=timestamp
            ),
        )
        blob_schedule.append(fork=cls.name(), schedule=current_blob_schedule)
        return blob_schedule

    @classmethod
    def tx_types(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[int]:
        """At Cancun, blob type transactions are introduced."""
        return [3] + super(Cancun, cls).tx_types(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def precompiles(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """At Cancun, a precompile for kzg point evaluation is introduced."""
        return [
            Address(10, label="KZG_POINT_EVALUATION"),
        ] + super(Cancun, cls).precompiles(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def system_contracts(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """Cancun introduces the system contract for EIP-4788."""
        del block_number, timestamp
        return [
            Address(
                0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02,
                label="BEACON_ROOTS_ADDRESS",
            )
        ]

    @classmethod
    def pre_allocation_blockchain(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Mapping:
        """
        Cancun requires pre-allocation of the beacon root contract for EIP-4788
        on blockchain type tests.
        """
        del block_number, timestamp
        new_allocation = {
            0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02: {
                "nonce": 1,
                "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d"
                "57602036146024575f5ffd5b5f35801560495762001fff810690"
                "815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd"
                "5b62001fff42064281555f359062001fff015500",
            }
        }
        return new_allocation | super(Cancun, cls).pre_allocation_blockchain()  # type: ignore

    @classmethod
    def engine_new_payload_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """From Cancun, new payload calls must use version 3."""
        del block_number, timestamp
        return 3

    @classmethod
    def engine_get_blobs_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """At Cancun, the engine get blobs version is 1."""
        del block_number, timestamp
        return 1

    @classmethod
    def engine_new_payload_blob_hashes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """From Cancun, payloads must have blob hashes."""
        del block_number, timestamp
        return True

    @classmethod
    def engine_new_payload_beacon_root(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """From Cancun, payloads must have a parent beacon block root."""
        del block_number, timestamp
        return True

    @classmethod
    def gas_costs(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> GasCosts:
        """On Cancun, the point evaluation precompile gas cost is set."""
        return replace(
            super(Cancun, cls).gas_costs(
                block_number=block_number, timestamp=timestamp
            ),
            G_PRECOMPILE_POINT_EVALUATION=50_000,
        )

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """
        Return a mapping of opcodes to their gas costs for Cancun.

        Adds Cancun-specific opcodes: BLOBHASH, BLOBBASEFEE, TLOAD, TSTORE,
        MCOPY.
        """
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        memory_expansion_calculator = cls.memory_expansion_gas_calculator(
            block_number=block_number, timestamp=timestamp
        )

        # Get parent fork's opcode gas map
        base_map = super(Cancun, cls).opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )

        # Add Cancun-specific opcodes
        return {
            **base_map,
            # EIP-4844: Shard Blob Transactions
            Opcodes.BLOBHASH: gas_costs.G_VERY_LOW,
            # EIP-7516: BLOBBASEFEE opcode
            Opcodes.BLOBBASEFEE: gas_costs.G_BASE,
            # EIP-1153: Transient storage opcodes
            Opcodes.TLOAD: gas_costs.G_WARM_SLOAD,
            Opcodes.TSTORE: gas_costs.G_WARM_SLOAD,
            # EIP-5656: MCOPY - Memory copying instruction
            Opcodes.MCOPY: cls._with_memory_expansion(
                cls._with_data_copy(gas_costs.G_VERY_LOW, gas_costs),
                memory_expansion_calculator,
            ),
        }

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [
            Opcodes.BLOBHASH,
            Opcodes.BLOBBASEFEE,
            Opcodes.TLOAD,
            Opcodes.TSTORE,
            Opcodes.MCOPY,
        ] + super(Cancun, cls).valid_opcodes()

get_blob_constant(name) classmethod

Return blob constant if it exists.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2316
2317
2318
2319
2320
2321
2322
2323
2324
@classmethod
def get_blob_constant(cls, name: str) -> int | Literal["big"]:
    """Return blob constant if it exists."""
    retrieved_constant = cls.BLOB_CONSTANTS.get(name)
    assert retrieved_constant is not None, (
        f"You tried to retrieve the blob constant {name} but it does "
        "not exist!"
    )
    return retrieved_constant

header_excess_blob_gas_required(*, block_number=0, timestamp=0) classmethod

Excess blob gas is required starting from Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2326
2327
2328
2329
2330
2331
2332
@classmethod
def header_excess_blob_gas_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Excess blob gas is required starting from Cancun."""
    del block_number, timestamp
    return True

header_blob_gas_used_required(*, block_number=0, timestamp=0) classmethod

Blob gas used is required starting from Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2334
2335
2336
2337
2338
2339
2340
@classmethod
def header_blob_gas_used_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Blob gas used is required starting from Cancun."""
    del block_number, timestamp
    return True

header_beacon_root_required(*, block_number=0, timestamp=0) classmethod

Parent beacon block root is required starting from Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2342
2343
2344
2345
2346
2347
2348
@classmethod
def header_beacon_root_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Parent beacon block root is required starting from Cancun."""
    del block_number, timestamp
    return True

blob_gas_price_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the blob gas price at Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
@classmethod
def blob_gas_price_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> BlobGasPriceCalculator:
    """Return a callable that calculates the blob gas price at Cancun."""
    min_base_fee_per_blob_gas = cls.min_base_fee_per_blob_gas(
        block_number=block_number, timestamp=timestamp
    )
    blob_base_fee_update_fraction = cls.blob_base_fee_update_fraction(
        block_number=block_number, timestamp=timestamp
    )

    def fn(*, excess_blob_gas: int) -> int:
        return fake_exponential(
            min_base_fee_per_blob_gas,
            excess_blob_gas,
            blob_base_fee_update_fraction,
        )

    return fn

excess_blob_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the excess blob gas for a block at Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
@classmethod
def excess_blob_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> ExcessBlobGasCalculator:
    """
    Return a callable that calculates the excess blob gas for a block at
    Cancun.
    """
    target_blobs_per_block = cls.target_blobs_per_block(
        block_number=block_number, timestamp=timestamp
    )
    blob_gas_per_blob = cls.blob_gas_per_blob(
        block_number=block_number, timestamp=timestamp
    )
    target_blob_gas_per_block = target_blobs_per_block * blob_gas_per_blob

    def fn(
        *,
        parent_excess_blob_gas: int | None = None,
        parent_excess_blobs: int | None = None,
        parent_blob_gas_used: int | None = None,
        parent_blob_count: int | None = None,
        # Required for Osaka as using this as base
        parent_base_fee_per_gas: int,
    ) -> int:
        del parent_base_fee_per_gas

        if parent_excess_blob_gas is None:
            assert parent_excess_blobs is not None, (
                "Parent excess blobs are required"
            )
            parent_excess_blob_gas = (
                parent_excess_blobs * blob_gas_per_blob
            )
        if parent_blob_gas_used is None:
            assert parent_blob_count is not None, (
                "Parent blob count is required"
            )
            parent_blob_gas_used = parent_blob_count * blob_gas_per_blob
        if (
            parent_excess_blob_gas + parent_blob_gas_used
            < target_blob_gas_per_block
        ):
            return 0
        else:
            return (
                parent_excess_blob_gas
                + parent_blob_gas_used
                - target_blob_gas_per_block
            )

    return fn

min_base_fee_per_blob_gas(*, block_number=0, timestamp=0) classmethod

Return the minimum base fee per blob gas for Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2424
2425
2426
2427
2428
2429
2430
@classmethod
def min_base_fee_per_blob_gas(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the minimum base fee per blob gas for Cancun."""
    del block_number, timestamp
    return 1

blob_base_fee_update_fraction(*, block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction for Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2432
2433
2434
2435
2436
2437
2438
@classmethod
def blob_base_fee_update_fraction(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the blob base fee update fraction for Cancun."""
    del block_number, timestamp
    return 3338477

blob_gas_per_blob(*, block_number=0, timestamp=0) classmethod

Blobs are enabled starting from Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2440
2441
2442
2443
2444
2445
2446
@classmethod
def blob_gas_per_blob(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs are enabled starting from Cancun."""
    del block_number, timestamp
    return 2**17

supports_blobs(*, block_number=0, timestamp=0) classmethod

At Cancun, blobs support is enabled.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2448
2449
2450
2451
2452
2453
2454
@classmethod
def supports_blobs(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At Cancun, blobs support is enabled."""
    del block_number, timestamp
    return True

target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs are enabled starting from Cancun, with a static target of 3 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
@classmethod
def target_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """
    Blobs are enabled starting from Cancun, with a static target of 3 blobs
    per block.
    """
    del block_number, timestamp
    return 3

max_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs are enabled starting from Cancun, with a static max of 6 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
@classmethod
def max_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """
    Blobs are enabled starting from Cancun, with a static max of 6 blobs
    per block.
    """
    del block_number, timestamp
    return 6

blob_reserve_price_active(*, block_number=0, timestamp=0) classmethod

Blob reserve price is not supported in Cancun.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2478
2479
2480
2481
2482
2483
2484
@classmethod
def blob_reserve_price_active(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Blob reserve price is not supported in Cancun."""
    del block_number, timestamp
    return False

full_blob_tx_wrapper_version(*, block_number=0, timestamp=0) classmethod

Pre-Osaka forks don't use tx wrapper versions for full blob transactions.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
@classmethod
def full_blob_tx_wrapper_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int | None:
    """
    Pre-Osaka forks don't use tx wrapper versions for full blob
    transactions.
    """
    del block_number, timestamp
    return None

max_blobs_per_tx(*, block_number=0, timestamp=0) classmethod

Blobs are enabled starting from Cancun, with a static max equal to the max per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
@classmethod
def max_blobs_per_tx(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """
    Blobs are enabled starting from Cancun, with a static max equal to the
    max per block.
    """
    return cls.max_blobs_per_block(
        block_number=block_number, timestamp=timestamp
    )

blob_schedule(*, block_number=0, timestamp=0) classmethod

At Cancun, the fork object runs this routine to get the updated blob schedule.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
@classmethod
def blob_schedule(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> BlobSchedule | None:
    """
    At Cancun, the fork object runs this routine to get the updated blob
    schedule.
    """
    parent_fork = cls.parent()
    assert parent_fork is not None, "Parent fork must be defined"
    blob_schedule = (
        parent_fork.blob_schedule(
            block_number=block_number, timestamp=timestamp
        )
        or BlobSchedule()
    )
    current_blob_schedule = ForkBlobSchedule(
        target_blobs_per_block=cls.target_blobs_per_block(
            block_number=block_number, timestamp=timestamp
        ),
        max_blobs_per_block=cls.max_blobs_per_block(
            block_number=block_number, timestamp=timestamp
        ),
        base_fee_update_fraction=cls.blob_base_fee_update_fraction(
            block_number=block_number, timestamp=timestamp
        ),
    )
    blob_schedule.append(fork=cls.name(), schedule=current_blob_schedule)
    return blob_schedule

tx_types(*, block_number=0, timestamp=0) classmethod

At Cancun, blob type transactions are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2539
2540
2541
2542
2543
2544
2545
2546
@classmethod
def tx_types(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[int]:
    """At Cancun, blob type transactions are introduced."""
    return [3] + super(Cancun, cls).tx_types(
        block_number=block_number, timestamp=timestamp
    )

precompiles(*, block_number=0, timestamp=0) classmethod

At Cancun, a precompile for kzg point evaluation is introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
@classmethod
def precompiles(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """At Cancun, a precompile for kzg point evaluation is introduced."""
    return [
        Address(10, label="KZG_POINT_EVALUATION"),
    ] + super(Cancun, cls).precompiles(
        block_number=block_number, timestamp=timestamp
    )

system_contracts(*, block_number=0, timestamp=0) classmethod

Cancun introduces the system contract for EIP-4788.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
@classmethod
def system_contracts(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """Cancun introduces the system contract for EIP-4788."""
    del block_number, timestamp
    return [
        Address(
            0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02,
            label="BEACON_ROOTS_ADDRESS",
        )
    ]

pre_allocation_blockchain(*, block_number=0, timestamp=0) classmethod

Cancun requires pre-allocation of the beacon root contract for EIP-4788 on blockchain type tests.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
@classmethod
def pre_allocation_blockchain(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Mapping:
    """
    Cancun requires pre-allocation of the beacon root contract for EIP-4788
    on blockchain type tests.
    """
    del block_number, timestamp
    new_allocation = {
        0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02: {
            "nonce": 1,
            "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d"
            "57602036146024575f5ffd5b5f35801560495762001fff810690"
            "815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd"
            "5b62001fff42064281555f359062001fff015500",
        }
    }
    return new_allocation | super(Cancun, cls).pre_allocation_blockchain()  # type: ignore

engine_new_payload_version(*, block_number=0, timestamp=0) classmethod

From Cancun, new payload calls must use version 3.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2592
2593
2594
2595
2596
2597
2598
@classmethod
def engine_new_payload_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """From Cancun, new payload calls must use version 3."""
    del block_number, timestamp
    return 3

engine_get_blobs_version(*, block_number=0, timestamp=0) classmethod

At Cancun, the engine get blobs version is 1.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2600
2601
2602
2603
2604
2605
2606
@classmethod
def engine_get_blobs_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """At Cancun, the engine get blobs version is 1."""
    del block_number, timestamp
    return 1

engine_new_payload_blob_hashes(*, block_number=0, timestamp=0) classmethod

From Cancun, payloads must have blob hashes.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2608
2609
2610
2611
2612
2613
2614
@classmethod
def engine_new_payload_blob_hashes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """From Cancun, payloads must have blob hashes."""
    del block_number, timestamp
    return True

engine_new_payload_beacon_root(*, block_number=0, timestamp=0) classmethod

From Cancun, payloads must have a parent beacon block root.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2616
2617
2618
2619
2620
2621
2622
@classmethod
def engine_new_payload_beacon_root(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """From Cancun, payloads must have a parent beacon block root."""
    del block_number, timestamp
    return True

gas_costs(*, block_number=0, timestamp=0) classmethod

On Cancun, the point evaluation precompile gas cost is set.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
@classmethod
def gas_costs(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> GasCosts:
    """On Cancun, the point evaluation precompile gas cost is set."""
    return replace(
        super(Cancun, cls).gas_costs(
            block_number=block_number, timestamp=timestamp
        ),
        G_PRECOMPILE_POINT_EVALUATION=50_000,
    )

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Return a mapping of opcodes to their gas costs for Cancun.

Adds Cancun-specific opcodes: BLOBHASH, BLOBBASEFEE, TLOAD, TSTORE, MCOPY.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """
    Return a mapping of opcodes to their gas costs for Cancun.

    Adds Cancun-specific opcodes: BLOBHASH, BLOBBASEFEE, TLOAD, TSTORE,
    MCOPY.
    """
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    memory_expansion_calculator = cls.memory_expansion_gas_calculator(
        block_number=block_number, timestamp=timestamp
    )

    # Get parent fork's opcode gas map
    base_map = super(Cancun, cls).opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )

    # Add Cancun-specific opcodes
    return {
        **base_map,
        # EIP-4844: Shard Blob Transactions
        Opcodes.BLOBHASH: gas_costs.G_VERY_LOW,
        # EIP-7516: BLOBBASEFEE opcode
        Opcodes.BLOBBASEFEE: gas_costs.G_BASE,
        # EIP-1153: Transient storage opcodes
        Opcodes.TLOAD: gas_costs.G_WARM_SLOAD,
        Opcodes.TSTORE: gas_costs.G_WARM_SLOAD,
        # EIP-5656: MCOPY - Memory copying instruction
        Opcodes.MCOPY: cls._with_memory_expansion(
            cls._with_data_copy(gas_costs.G_VERY_LOW, gas_costs),
            memory_expansion_calculator,
        ),
    }

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [
        Opcodes.BLOBHASH,
        Opcodes.BLOBBASEFEE,
        Opcodes.TLOAD,
        Opcodes.TSTORE,
        Opcodes.MCOPY,
    ] + super(Cancun, cls).valid_opcodes()

Constantinople

Bases: Byzantium

Constantinople fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
class Constantinople(Byzantium):
    """Constantinople fork."""

    @classmethod
    def get_reward(cls, *, block_number: int = 0, timestamp: int = 0) -> int:
        """
        At Constantinople, the block reward is reduced to
        2_000_000_000_000_000_000 wei.
        """
        del block_number, timestamp
        return 2_000_000_000_000_000_000

    @classmethod
    def _calculate_create2_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """Calculate CREATE2 gas cost based on metadata."""
        metadata = opcode.metadata

        # Keccak256 hashing cost
        init_code_size = metadata["init_code_size"]
        init_code_words = (init_code_size + 31) // 32
        hash_gas = gas_costs.G_KECCAK_256_WORD * init_code_words

        return gas_costs.G_CREATE + hash_gas

    @classmethod
    def create_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """At Constantinople, `CREATE2` opcode is added."""
        return [Opcodes.CREATE2] + super(Constantinople, cls).create_opcodes(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """Add Constantinople opcodes gas costs."""
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        memory_expansion_calculator = cls.memory_expansion_gas_calculator(
            block_number=block_number, timestamp=timestamp
        )
        base_map = super(Constantinople, cls).opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )
        return {
            **base_map,
            Opcodes.SHL: gas_costs.G_VERY_LOW,
            Opcodes.SHR: gas_costs.G_VERY_LOW,
            Opcodes.SAR: gas_costs.G_VERY_LOW,
            Opcodes.EXTCODEHASH: cls._with_account_access(0, gas_costs),
            Opcodes.CREATE2: cls._with_memory_expansion(
                lambda op: cls._calculate_create2_gas(op, gas_costs),
                memory_expansion_calculator,
            ),
        }

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [
            Opcodes.SHL,
            Opcodes.SHR,
            Opcodes.SAR,
            Opcodes.EXTCODEHASH,
            Opcodes.CREATE2,
        ] + super(Constantinople, cls).valid_opcodes()

get_reward(*, block_number=0, timestamp=0) classmethod

At Constantinople, the block reward is reduced to 2_000_000_000_000_000_000 wei.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1720
1721
1722
1723
1724
1725
1726
1727
@classmethod
def get_reward(cls, *, block_number: int = 0, timestamp: int = 0) -> int:
    """
    At Constantinople, the block reward is reduced to
    2_000_000_000_000_000_000 wei.
    """
    del block_number, timestamp
    return 2_000_000_000_000_000_000

create_opcodes(*, block_number=0, timestamp=0) classmethod

At Constantinople, CREATE2 opcode is added.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1743
1744
1745
1746
1747
1748
1749
1750
@classmethod
def create_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """At Constantinople, `CREATE2` opcode is added."""
    return [Opcodes.CREATE2] + super(Constantinople, cls).create_opcodes(
        block_number=block_number, timestamp=timestamp
    )

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Add Constantinople opcodes gas costs.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """Add Constantinople opcodes gas costs."""
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    memory_expansion_calculator = cls.memory_expansion_gas_calculator(
        block_number=block_number, timestamp=timestamp
    )
    base_map = super(Constantinople, cls).opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )
    return {
        **base_map,
        Opcodes.SHL: gas_costs.G_VERY_LOW,
        Opcodes.SHR: gas_costs.G_VERY_LOW,
        Opcodes.SAR: gas_costs.G_VERY_LOW,
        Opcodes.EXTCODEHASH: cls._with_account_access(0, gas_costs),
        Opcodes.CREATE2: cls._with_memory_expansion(
            lambda op: cls._calculate_create2_gas(op, gas_costs),
            memory_expansion_calculator,
        ),
    }

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [
        Opcodes.SHL,
        Opcodes.SHR,
        Opcodes.SAR,
        Opcodes.EXTCODEHASH,
        Opcodes.CREATE2,
    ] + super(Constantinople, cls).valid_opcodes()

ConstantinopleFix

Bases: Constantinople

Constantinople Fix fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1793
1794
1795
1796
class ConstantinopleFix(Constantinople, solc_name="constantinople"):
    """Constantinople Fix fork."""

    pass

Frontier

Bases: BaseFork

Frontier fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
class Frontier(BaseFork, solc_name="homestead"):
    """Frontier fork."""

    @classmethod
    def transition_tool_name(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> str:
        """
        Return fork name as it's meant to be passed to the transition tool for
        execution.
        """
        del block_number, timestamp
        if cls._transition_tool_name is not None:
            return cls._transition_tool_name
        return cls.name()

    @classmethod
    def solc_name(cls) -> str:
        """Return fork name as it's meant to be passed to the solc compiler."""
        if cls._solc_name is not None:
            return cls._solc_name
        return cls.name().lower()

    @classmethod
    def header_base_fee_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not contain base fee."""
        del block_number, timestamp
        return False

    @classmethod
    def header_prev_randao_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not contain Prev Randao value."""
        del block_number, timestamp
        return False

    @classmethod
    def header_zero_difficulty_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not have difficulty zero."""
        del block_number, timestamp
        return False

    @classmethod
    def header_withdrawals_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not contain withdrawals."""
        del block_number, timestamp
        return False

    @classmethod
    def header_excess_blob_gas_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not contain excess blob gas."""
        del block_number, timestamp
        return False

    @classmethod
    def header_blob_gas_used_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not contain blob gas used."""
        del block_number, timestamp
        return False

    @classmethod
    def gas_costs(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> GasCosts:
        """
        Return dataclass with the defined gas costs constants for genesis.
        """
        del block_number, timestamp
        return GasCosts(
            G_JUMPDEST=1,
            G_BASE=2,
            G_VERY_LOW=3,
            G_LOW=5,
            G_MID=8,
            G_HIGH=10,
            G_WARM_ACCOUNT_ACCESS=100,
            G_COLD_ACCOUNT_ACCESS=2_600,
            G_ACCESS_LIST_ADDRESS=2_400,
            G_ACCESS_LIST_STORAGE=1_900,
            G_WARM_SLOAD=100,
            G_COLD_SLOAD=2_100,
            G_STORAGE_SET=20_000,
            G_STORAGE_UPDATE=5_000,
            G_STORAGE_RESET=2_900,
            R_STORAGE_CLEAR=4_800,
            G_SELF_DESTRUCT=5_000,
            G_CREATE=32_000,
            G_CODE_DEPOSIT_BYTE=200,
            G_INITCODE_WORD=2,
            G_CALL_VALUE=9_000,
            G_CALL_STIPEND=2_300,
            G_NEW_ACCOUNT=25_000,
            G_EXP=10,
            G_EXP_BYTE=50,
            G_MEMORY=3,
            G_TX_DATA_ZERO=4,
            G_TX_DATA_NON_ZERO=68,
            G_TRANSACTION=21_000,
            G_TRANSACTION_CREATE=32_000,
            G_LOG=375,
            G_LOG_DATA=8,
            G_LOG_TOPIC=375,
            G_KECCAK_256=30,
            G_KECCAK_256_WORD=6,
            G_COPY=3,
            G_BLOCKHASH=20,
            G_PRECOMPILE_ECRECOVER=3_000,
            G_PRECOMPILE_SHA256_BASE=60,
            G_PRECOMPILE_SHA256_WORD=12,
            G_PRECOMPILE_RIPEMD160_BASE=600,
            G_PRECOMPILE_RIPEMD160_WORD=120,
            G_PRECOMPILE_IDENTITY_BASE=15,
            G_PRECOMPILE_IDENTITY_WORD=3,
            # Zero-initialized: introduced in later forks, set via
            # replace() in the fork that activates them.
            G_TX_DATA_STANDARD_TOKEN_COST=0,
            G_TX_DATA_FLOOR_TOKEN_COST=0,
            G_AUTHORIZATION=0,
            R_AUTHORIZATION_EXISTING_AUTHORITY=0,
            G_PRECOMPILE_ECADD=0,
            G_PRECOMPILE_ECMUL=0,
            G_PRECOMPILE_ECPAIRING_BASE=0,
            G_PRECOMPILE_ECPAIRING_PER_POINT=0,
            G_PRECOMPILE_BLAKE2F_BASE=0,
            G_PRECOMPILE_BLAKE2F_PER_ROUND=0,
            G_PRECOMPILE_POINT_EVALUATION=0,
            G_PRECOMPILE_BLS_G1ADD=0,
            G_PRECOMPILE_BLS_G1MUL=0,
            G_PRECOMPILE_BLS_G1MAP=0,
            G_PRECOMPILE_BLS_G2ADD=0,
            G_PRECOMPILE_BLS_G2MUL=0,
            G_PRECOMPILE_BLS_G2MAP=0,
            G_PRECOMPILE_BLS_PAIRING_BASE=0,
            G_PRECOMPILE_BLS_PAIRING_PER_PAIR=0,
            G_PRECOMPILE_P256VERIFY=0,
        )

    @classmethod
    def _with_memory_expansion(
        cls,
        base_gas: int | Callable[[OpcodeBase], int],
        memory_expansion_gas_calculator: MemoryExpansionGasCalculator,
    ) -> Callable[[OpcodeBase], int]:
        """
        Wrap a gas cost calculator to include memory expansion cost.

        Args:
            base_gas: Either a constant gas cost (int) or a callable that
                      calculates it
            memory_expansion_gas_calculator: Calculator for memory expansion
                                             cost

        Returns:
            A callable that calculates base_gas + memory_expansion_cost

        """

        def wrapper(opcode: OpcodeBase) -> int:
            # Calculate base gas cost
            if callable(base_gas):
                base_cost = base_gas(opcode)
            else:
                base_cost = base_gas

            # Add memory expansion cost if metadata is present
            new_memory_size = opcode.metadata["new_memory_size"]
            old_memory_size = opcode.metadata["old_memory_size"]
            expansion_cost = memory_expansion_gas_calculator(
                new_bytes=new_memory_size, previous_bytes=old_memory_size
            )

            return base_cost + expansion_cost

        return wrapper

    @classmethod
    def _with_account_access(
        cls,
        base_gas: int | Callable[[OpcodeBase], int],
        gas_costs: "GasCosts",
    ) -> Callable[[OpcodeBase], int]:
        """
        Wrap a gas cost calculator to include account access cost.

        Args:
            base_gas: Either a constant gas cost (int) or a callable that
                      calculates it
            gas_costs: The gas costs dataclass for accessing warm/cold costs

        Returns:
            A callable that calculates base_gas + account_access_cost

        """

        def wrapper(opcode: OpcodeBase) -> int:
            # Calculate base gas cost
            if callable(base_gas):
                base_cost = base_gas(opcode)
            else:
                base_cost = base_gas

            # Add account access cost based on warmth
            if opcode.metadata["address_warm"]:
                access_cost = gas_costs.G_WARM_ACCOUNT_ACCESS
            else:
                access_cost = gas_costs.G_COLD_ACCOUNT_ACCESS

            return base_cost + access_cost

        return wrapper

    @classmethod
    def _with_data_copy(
        cls,
        base_gas: int | Callable[[OpcodeBase], int],
        gas_costs: "GasCosts",
    ) -> Callable[[OpcodeBase], int]:
        """
        Wrap a gas cost calculator to include data copy cost.

        Args:
            base_gas: Either a constant gas cost (int) or a callable that
                      calculates it
            gas_costs: The gas costs dataclass for accessing G_COPY

        Returns:
            A callable that calculates base_gas + copy_cost

        """

        def wrapper(opcode: OpcodeBase) -> int:
            # Calculate base gas cost
            if callable(base_gas):
                base_cost = base_gas(opcode)
            else:
                base_cost = base_gas

            # Add copy cost based on data size
            data_size = opcode.metadata["data_size"]
            word_count = (data_size + 31) // 32
            copy_cost = gas_costs.G_COPY * word_count

            return base_cost + copy_cost

        return wrapper

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """
        Return a mapping of opcodes to their gas costs.

        Each entry is either:
        - Constants (int): Direct gas cost values from gas_costs()
        - Callables: Functions that take the opcode instance with metadata and
                     return gas cost
        """
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        memory_expansion_calculator = cls.memory_expansion_gas_calculator(
            block_number=block_number, timestamp=timestamp
        )

        # Define the opcode gas cost mapping
        # Each entry is either:
        # - an int (constant cost)
        # - a callable(opcode) -> int
        return {
            # Stop and arithmetic operations
            Opcodes.STOP: 0,
            Opcodes.ADD: gas_costs.G_VERY_LOW,
            Opcodes.MUL: gas_costs.G_LOW,
            Opcodes.SUB: gas_costs.G_VERY_LOW,
            Opcodes.DIV: gas_costs.G_LOW,
            Opcodes.SDIV: gas_costs.G_LOW,
            Opcodes.MOD: gas_costs.G_LOW,
            Opcodes.SMOD: gas_costs.G_LOW,
            Opcodes.ADDMOD: gas_costs.G_MID,
            Opcodes.MULMOD: gas_costs.G_MID,
            Opcodes.EXP: lambda op: (
                gas_costs.G_EXP
                + gas_costs.G_EXP_BYTE
                * ((op.metadata["exponent"].bit_length() + 7) // 8)
            ),
            Opcodes.SIGNEXTEND: gas_costs.G_LOW,
            # Comparison & bitwise logic operations
            Opcodes.LT: gas_costs.G_VERY_LOW,
            Opcodes.GT: gas_costs.G_VERY_LOW,
            Opcodes.SLT: gas_costs.G_VERY_LOW,
            Opcodes.SGT: gas_costs.G_VERY_LOW,
            Opcodes.EQ: gas_costs.G_VERY_LOW,
            Opcodes.ISZERO: gas_costs.G_VERY_LOW,
            Opcodes.AND: gas_costs.G_VERY_LOW,
            Opcodes.OR: gas_costs.G_VERY_LOW,
            Opcodes.XOR: gas_costs.G_VERY_LOW,
            Opcodes.NOT: gas_costs.G_VERY_LOW,
            Opcodes.BYTE: gas_costs.G_VERY_LOW,
            # SHA3
            Opcodes.SHA3: cls._with_memory_expansion(
                lambda op: (
                    gas_costs.G_KECCAK_256
                    + gas_costs.G_KECCAK_256_WORD
                    * ((op.metadata["data_size"] + 31) // 32)
                ),
                memory_expansion_calculator,
            ),
            # Environmental information
            Opcodes.ADDRESS: gas_costs.G_BASE,
            Opcodes.BALANCE: cls._with_account_access(0, gas_costs),
            Opcodes.ORIGIN: gas_costs.G_BASE,
            Opcodes.CALLER: gas_costs.G_BASE,
            Opcodes.CALLVALUE: gas_costs.G_BASE,
            Opcodes.CALLDATALOAD: gas_costs.G_VERY_LOW,
            Opcodes.CALLDATASIZE: gas_costs.G_BASE,
            Opcodes.CALLDATACOPY: cls._with_memory_expansion(
                cls._with_data_copy(gas_costs.G_VERY_LOW, gas_costs),
                memory_expansion_calculator,
            ),
            Opcodes.CODESIZE: gas_costs.G_BASE,
            Opcodes.CODECOPY: cls._with_memory_expansion(
                cls._with_data_copy(gas_costs.G_VERY_LOW, gas_costs),
                memory_expansion_calculator,
            ),
            Opcodes.GASPRICE: gas_costs.G_BASE,
            Opcodes.EXTCODESIZE: cls._with_account_access(0, gas_costs),
            Opcodes.EXTCODECOPY: cls._with_memory_expansion(
                cls._with_data_copy(
                    cls._with_account_access(0, gas_costs),
                    gas_costs,
                ),
                memory_expansion_calculator,
            ),
            # Block information
            Opcodes.BLOCKHASH: gas_costs.G_BLOCKHASH,
            Opcodes.COINBASE: gas_costs.G_BASE,
            Opcodes.TIMESTAMP: gas_costs.G_BASE,
            Opcodes.NUMBER: gas_costs.G_BASE,
            Opcodes.PREVRANDAO: gas_costs.G_BASE,
            Opcodes.GASLIMIT: gas_costs.G_BASE,
            # Stack, memory, storage and flow operations
            Opcodes.POP: gas_costs.G_BASE,
            Opcodes.MLOAD: cls._with_memory_expansion(
                gas_costs.G_VERY_LOW, memory_expansion_calculator
            ),
            Opcodes.MSTORE: cls._with_memory_expansion(
                gas_costs.G_VERY_LOW, memory_expansion_calculator
            ),
            Opcodes.MSTORE8: cls._with_memory_expansion(
                gas_costs.G_VERY_LOW, memory_expansion_calculator
            ),
            Opcodes.SLOAD: lambda op: (
                gas_costs.G_WARM_SLOAD
                if op.metadata["key_warm"]
                else gas_costs.G_COLD_SLOAD
            ),
            Opcodes.SSTORE: lambda op: cls._calculate_sstore_gas(
                op, gas_costs
            ),
            Opcodes.JUMP: gas_costs.G_MID,
            Opcodes.JUMPI: gas_costs.G_HIGH,
            Opcodes.PC: gas_costs.G_BASE,
            Opcodes.MSIZE: gas_costs.G_BASE,
            Opcodes.GAS: gas_costs.G_BASE,
            Opcodes.JUMPDEST: gas_costs.G_JUMPDEST,
            # Push operations (PUSH1 through PUSH32)
            **{
                getattr(Opcodes, f"PUSH{i}"): gas_costs.G_VERY_LOW
                for i in range(1, 33)
            },
            # Dup operations (DUP1 through DUP16)
            **{
                getattr(Opcodes, f"DUP{i}"): gas_costs.G_VERY_LOW
                for i in range(1, 17)
            },
            # Swap operations (SWAP1 through SWAP16)
            **{
                getattr(Opcodes, f"SWAP{i}"): gas_costs.G_VERY_LOW
                for i in range(1, 17)
            },
            # Logging operations
            Opcodes.LOG0: cls._with_memory_expansion(
                lambda op: (
                    gas_costs.G_LOG
                    + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                ),
                memory_expansion_calculator,
            ),
            Opcodes.LOG1: cls._with_memory_expansion(
                lambda op: (
                    gas_costs.G_LOG
                    + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                    + gas_costs.G_LOG_TOPIC
                ),
                memory_expansion_calculator,
            ),
            Opcodes.LOG2: cls._with_memory_expansion(
                lambda op: (
                    gas_costs.G_LOG
                    + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                    + gas_costs.G_LOG_TOPIC * 2
                ),
                memory_expansion_calculator,
            ),
            Opcodes.LOG3: cls._with_memory_expansion(
                lambda op: (
                    gas_costs.G_LOG
                    + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                    + gas_costs.G_LOG_TOPIC * 3
                ),
                memory_expansion_calculator,
            ),
            Opcodes.LOG4: cls._with_memory_expansion(
                lambda op: (
                    gas_costs.G_LOG
                    + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                    + gas_costs.G_LOG_TOPIC * 4
                ),
                memory_expansion_calculator,
            ),
            # System operations
            Opcodes.CREATE: cls._with_memory_expansion(
                lambda op: cls._calculate_create_gas(op, gas_costs),
                memory_expansion_calculator,
            ),
            Opcodes.CALL: cls._with_memory_expansion(
                lambda op: cls._calculate_call_gas(op, gas_costs),
                memory_expansion_calculator,
            ),
            Opcodes.CALLCODE: cls._with_memory_expansion(
                lambda op: cls._calculate_call_gas(op, gas_costs),
                memory_expansion_calculator,
            ),
            Opcodes.RETURN: cls._with_memory_expansion(
                lambda op: cls._calculate_return_gas(op, gas_costs),
                memory_expansion_calculator,
            ),
            Opcodes.INVALID: 0,
            Opcodes.SELFDESTRUCT: lambda op: cls._calculate_selfdestruct_gas(
                op, gas_costs
            ),
        }

    @classmethod
    def opcode_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> OpcodeGasCalculator:
        """
        Return callable that calculates the gas cost of a single opcode.
        """
        opcode_gas_map = cls.opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )

        def fn(opcode: OpcodeBase) -> int:
            # Get the gas cost or calculator
            if opcode not in opcode_gas_map:
                raise ValueError(
                    f"No gas cost defined for opcode: {opcode._name_}"
                )
            gas_cost_or_calculator = opcode_gas_map[opcode]

            # If it's a callable, call it with the opcode
            if callable(gas_cost_or_calculator):
                return gas_cost_or_calculator(opcode)

            # Otherwise it's a constant
            return gas_cost_or_calculator

        return fn

    @classmethod
    def opcode_refund_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """
        Return a mapping of opcodes to their gas refunds.

        Each entry is either:
        - Constants (int): Direct gas refund values
        - Callables: Functions that take the opcode instance with metadata and
                     return gas refund
        """
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )

        # Only SSTORE provides refunds
        return {
            Opcodes.SSTORE: lambda op: cls._calculate_sstore_refund(
                op, gas_costs
            ),
        }

    @classmethod
    def opcode_refund_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> OpcodeGasCalculator:
        """
        Return callable that calculates the gas refund of a single opcode.
        """
        opcode_refund_map = cls.opcode_refund_map(
            block_number=block_number, timestamp=timestamp
        )

        def fn(opcode: OpcodeBase) -> int:
            # Get the gas refund or calculator
            if opcode not in opcode_refund_map:
                # Most opcodes don't provide refunds
                return 0
            refund_or_calculator = opcode_refund_map[opcode]

            # If it's a callable, call it with the opcode
            if callable(refund_or_calculator):
                return refund_or_calculator(opcode)

            # Otherwise it's a constant
            return refund_or_calculator

        return fn

    @classmethod
    def _calculate_sstore_refund(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """Calculate SSTORE gas refund based on metadata."""
        metadata = opcode.metadata

        original_value = metadata["original_value"]
        current_value = metadata["current_value"]
        if current_value is None:
            current_value = original_value
        new_value = metadata["new_value"]

        # Refund is provided when setting from non-zero to zero
        refund = 0
        if current_value != new_value:
            if original_value != 0 and current_value != 0 and new_value == 0:
                # Storage is cleared for the first time in the transaction
                refund += gas_costs.R_STORAGE_CLEAR

            if original_value != 0 and current_value == 0:
                # Gas refund issued earlier to be reversed
                refund -= gas_costs.R_STORAGE_CLEAR

            if original_value == new_value:
                # Storage slot being restored to its original value
                if original_value == 0:
                    # Slot was originally empty and was SET earlier
                    refund += gas_costs.G_STORAGE_SET - gas_costs.G_WARM_SLOAD
                else:
                    # Slot was originally non-empty and was UPDATED earlier
                    refund += (
                        gas_costs.G_STORAGE_UPDATE
                        - gas_costs.G_COLD_SLOAD
                        - gas_costs.G_WARM_SLOAD
                    )

        return refund

    @classmethod
    def _calculate_sstore_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """Calculate SSTORE gas cost based on metadata."""
        metadata = opcode.metadata

        original_value = metadata["original_value"]
        current_value = metadata["current_value"]
        if current_value is None:
            current_value = original_value
        new_value = metadata["new_value"]

        gas_cost = 0 if metadata["key_warm"] else gas_costs.G_COLD_SLOAD

        if original_value == current_value and current_value != new_value:
            if original_value == 0:
                gas_cost += gas_costs.G_STORAGE_SET
            else:
                gas_cost += gas_costs.G_STORAGE_UPDATE - gas_costs.G_COLD_SLOAD
        else:
            gas_cost += gas_costs.G_WARM_SLOAD

        return gas_cost

    @classmethod
    def _calculate_call_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """
        Calculate CALL/DELEGATECALL/STATICCALL gas cost based on metadata.
        """
        metadata = opcode.metadata

        # Base cost depends on address warmth
        if metadata["address_warm"]:
            base_cost = gas_costs.G_WARM_ACCOUNT_ACCESS
        else:
            base_cost = gas_costs.G_COLD_ACCOUNT_ACCESS

        return base_cost

    @classmethod
    def _calculate_create_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """CREATE gas is constant at Frontier."""
        del opcode
        return gas_costs.G_CREATE

    @classmethod
    def _calculate_return_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """Calculate RETURN gas cost based on metadata."""
        metadata = opcode.metadata

        # Code deposit cost when returning from initcode
        code_deposit_size = metadata["code_deposit_size"]
        return gas_costs.G_CODE_DEPOSIT_BYTE * code_deposit_size

    @classmethod
    def _calculate_selfdestruct_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """Calculate SELFDESTRUCT gas cost based on metadata."""
        metadata = opcode.metadata

        base_cost = gas_costs.G_SELF_DESTRUCT

        # Check if the beneficiary is cold
        if not metadata["address_warm"]:
            base_cost += gas_costs.G_COLD_ACCOUNT_ACCESS

        # Check if creating a new account
        if metadata["account_new"]:
            base_cost += gas_costs.G_NEW_ACCOUNT

        return base_cost

    @classmethod
    def memory_expansion_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> MemoryExpansionGasCalculator:
        """
        Return callable that calculates the gas cost of memory expansion for
        the fork.
        """
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )

        def fn(*, new_bytes: int, previous_bytes: int = 0) -> int:
            if new_bytes <= previous_bytes:
                return 0
            new_words = ceiling_division(new_bytes, 32)
            previous_words = ceiling_division(previous_bytes, 32)

            def c(w: int) -> int:
                return (gas_costs.G_MEMORY * w) + ((w * w) // 512)

            return c(new_words) - c(previous_words)

        return fn

    @classmethod
    def calldata_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> CalldataGasCalculator:
        """
        Return callable that calculates the transaction gas cost for its
        calldata depending on its contents.
        """
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )

        def fn(*, data: BytesConvertible, floor: bool = False) -> int:
            del floor

            cost = 0
            for b in Bytes(data):
                if b == 0:
                    cost += gas_costs.G_TX_DATA_ZERO
                else:
                    cost += gas_costs.G_TX_DATA_NON_ZERO
            return cost

        return fn

    @classmethod
    def base_fee_per_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> BaseFeePerGasCalculator:
        """
        Return a callable that calculates the base fee per gas at a given fork.
        """
        raise NotImplementedError(
            f"Base fee per gas calculator is not supported in {cls.name()}"
        )

    @classmethod
    def base_fee_change_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> BaseFeeChangeCalculator:
        """
        Return a callable that calculates the gas that needs to be used to
        change the base fee.
        """
        raise NotImplementedError(
            f"Base fee change calculator is not supported in {cls.name()}"
        )

    @classmethod
    def base_fee_max_change_denominator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the base fee max change denominator at a given fork."""
        del block_number, timestamp
        raise NotImplementedError(
            f"Base fee max change denominator is not supported in {cls.name()}"
        )

    @classmethod
    def base_fee_elasticity_multiplier(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the base fee elasticity multiplier at a given fork."""
        del block_number, timestamp
        raise NotImplementedError(
            f"Base fee elasticity multiplier is not supported in {cls.name()}"
        )

    @classmethod
    def transaction_data_floor_cost_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> TransactionDataFloorCostCalculator:
        """At frontier, the transaction data floor cost is a constant zero."""
        del block_number, timestamp

        def fn(*, data: BytesConvertible) -> int:
            del data
            return 0

        return fn

    @classmethod
    def transaction_intrinsic_cost_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> TransactionIntrinsicCostCalculator:
        """
        Return callable that calculates the intrinsic gas cost of a transaction
        for the fork.
        """
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        calldata_gas_calculator = cls.calldata_gas_calculator(
            block_number=block_number, timestamp=timestamp
        )

        def fn(
            *,
            calldata: BytesConvertible = b"",
            contract_creation: bool = False,
            access_list: List[AccessList] | None = None,
            authorization_list_or_count: Sized | int | None = None,
            return_cost_deducted_prior_execution: bool = False,
        ) -> int:
            del return_cost_deducted_prior_execution

            assert access_list is None, (
                f"Access list is not supported in {cls.name()}"
            )
            assert authorization_list_or_count is None, (
                f"Authorizations are not supported in {cls.name()}"
            )

            intrinsic_cost: int = gas_costs.G_TRANSACTION

            if contract_creation:
                intrinsic_cost += gas_costs.G_INITCODE_WORD * ceiling_division(
                    len(Bytes(calldata)), 32
                )

            return intrinsic_cost + calldata_gas_calculator(data=calldata)

        return fn

    @classmethod
    def blob_gas_price_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> BlobGasPriceCalculator:
        """
        Return a callable that calculates the blob gas price at a given fork.
        """
        raise NotImplementedError(
            f"Blob gas price calculator is not supported in {cls.name()}"
        )

    @classmethod
    def excess_blob_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> ExcessBlobGasCalculator:
        """
        Return a callable that calculates the excess blob gas for a block at a
        given fork.
        """
        raise NotImplementedError(
            f"Excess blob gas calculator is not supported in {cls.name()}"
        )

    @classmethod
    def min_base_fee_per_blob_gas(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the amount of blob gas used per blob at a given fork."""
        del block_number, timestamp
        raise NotImplementedError(
            f"Base fee per blob gas is not supported in {cls.name()}"
        )

    @classmethod
    def blob_base_fee_update_fraction(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the blob base fee update fraction at a given fork."""
        del block_number, timestamp
        raise NotImplementedError(
            f"Blob base fee update fraction is not supported in {cls.name()}"
        )

    @classmethod
    def blob_gas_per_blob(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the amount of blob gas used per blob at a given fork."""
        del block_number, timestamp
        return 0

    @classmethod
    def supports_blobs(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Blobs are not supported at Frontier."""
        del block_number, timestamp
        return False

    @classmethod
    def target_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the target number of blobs per block at a given fork."""
        del block_number, timestamp
        raise NotImplementedError(
            f"Target blobs per block is not supported in {cls.name()}"
        )

    @classmethod
    def max_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the max number of blobs per block at a given fork."""
        del block_number, timestamp
        raise NotImplementedError(
            f"Max blobs per block is not supported in {cls.name()}"
        )

    @classmethod
    def blob_reserve_price_active(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """
        Return whether the fork uses a reserve price mechanism for blobs or
        not.
        """
        del block_number, timestamp
        raise NotImplementedError(
            f"Blob reserve price is not supported in {cls.name()}"
        )

    @classmethod
    def blob_base_cost(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the base cost of a blob at a given fork."""
        del block_number, timestamp
        raise NotImplementedError(
            f"Blob base cost is not supported in {cls.name()}"
        )

    @classmethod
    def full_blob_tx_wrapper_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int | None:
        """Return the version of the full blob transaction wrapper."""
        raise NotImplementedError(
            "Full blob transaction wrapper version is not supported in "
            f"{cls.name()}"
        )

    @classmethod
    def max_blobs_per_tx(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the max number of blobs per tx at a given fork."""
        del block_number, timestamp
        raise NotImplementedError(
            f"Max blobs per tx is not supported in {cls.name()}"
        )

    @classmethod
    def blob_schedule(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> BlobSchedule | None:
        """At genesis, no blob schedule is used."""
        del block_number, timestamp
        return None

    @classmethod
    def header_requests_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not contain beacon chain requests."""
        del block_number, timestamp
        return False

    @classmethod
    def header_bal_hash_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not contain block access list hash."""
        del block_number, timestamp
        return False

    @classmethod
    def engine_new_payload_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """At genesis, payloads cannot be sent through the engine API."""
        del block_number, timestamp
        return None

    @classmethod
    def header_beacon_root_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, header must not contain parent beacon block root."""
        del block_number, timestamp
        return False

    @classmethod
    def engine_new_payload_blob_hashes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, payloads do not have blob hashes."""
        del block_number, timestamp
        return False

    @classmethod
    def engine_new_payload_beacon_root(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, payloads do not have a parent beacon block root."""
        del block_number, timestamp
        return False

    @classmethod
    def engine_new_payload_requests(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, payloads do not have requests."""
        del block_number, timestamp
        return False

    @classmethod
    def engine_execution_payload_block_access_list(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """At genesis, payloads do not have block access list."""
        del block_number, timestamp
        return False

    @classmethod
    def engine_new_payload_target_blobs_per_block(
        cls,
        *,
        block_number: int = 0,
        timestamp: int = 0,
    ) -> bool:
        """At genesis, payloads do not have target blobs per block."""
        del block_number, timestamp
        return False

    @classmethod
    def engine_payload_attribute_target_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """
        At genesis, payload attributes do not include the target blobs per
        block.
        """
        del block_number, timestamp
        return False

    @classmethod
    def engine_payload_attribute_max_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """
        At genesis, payload attributes do not include the max blobs per block.
        """
        del block_number, timestamp
        return False

    @classmethod
    def engine_forkchoice_updated_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """
        At genesis, forkchoice updates cannot be sent through the engine API.
        """
        return cls.engine_new_payload_version(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def engine_get_payload_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """At genesis, payloads cannot be retrieved through the engine API."""
        return cls.engine_new_payload_version(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def engine_get_blobs_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """At genesis, blobs cannot be retrieved through the engine API."""
        del block_number, timestamp
        return None

    @classmethod
    def get_reward(cls, *, block_number: int = 0, timestamp: int = 0) -> int:
        """
        At Genesis the expected reward amount in wei is
        5_000_000_000_000_000_000.
        """
        del block_number, timestamp
        return 5_000_000_000_000_000_000

    @classmethod
    def supports_protected_txs(cls) -> bool:
        """At Genesis, fork has no support for EIP-155 protected txs."""
        return False

    @classmethod
    def tx_types(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[int]:
        """At Genesis, only legacy transactions are allowed."""
        del block_number, timestamp
        return [0]

    @classmethod
    def contract_creating_tx_types(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[int]:
        """At Genesis, only legacy transactions are allowed."""
        del block_number, timestamp
        return [0]

    @classmethod
    def transaction_gas_limit_cap(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int | None:
        """At Genesis, no transaction gas limit cap is imposed."""
        del block_number, timestamp
        return None

    @classmethod
    def block_rlp_size_limit(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int | None:
        """At Genesis, no RLP block size limit is imposed."""
        del block_number, timestamp
        return None

    @classmethod
    def precompiles(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """At Genesis, no precompiles are present."""
        del block_number, timestamp
        return []

    @classmethod
    def system_contracts(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """At Genesis, no system contracts are present."""
        del block_number, timestamp
        return []

    @classmethod
    def deterministic_factory_predeploy_address(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Address | None:
        """At Genesis, no deterministic factory predeploy is present."""
        del block_number, timestamp
        return None

    @classmethod
    def max_code_size(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """
        At genesis, there is no upper bound for code size (bounded by block gas
        limit).

        However, the default is set to the limit of EIP-170 (Spurious Dragon)
        """
        del block_number, timestamp
        return 0x6000

    @classmethod
    def max_stack_height(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """At genesis, the maximum stack height is 1024."""
        del block_number, timestamp
        return 1024

    @classmethod
    def max_initcode_size(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """
        At genesis, there is no upper bound for initcode size.

        However, the default is set to the limit of EIP-3860 (Shanghai).
        """
        del block_number, timestamp
        return 0xC000

    @classmethod
    def call_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of call opcodes supported by the fork."""
        del block_number, timestamp
        return [Opcodes.CALL, Opcodes.CALLCODE]

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [
            Opcodes.STOP,
            Opcodes.ADD,
            Opcodes.MUL,
            Opcodes.SUB,
            Opcodes.DIV,
            Opcodes.SDIV,
            Opcodes.MOD,
            Opcodes.SMOD,
            Opcodes.ADDMOD,
            Opcodes.MULMOD,
            Opcodes.EXP,
            Opcodes.SIGNEXTEND,
            Opcodes.LT,
            Opcodes.GT,
            Opcodes.SLT,
            Opcodes.SGT,
            Opcodes.EQ,
            Opcodes.ISZERO,
            Opcodes.AND,
            Opcodes.OR,
            Opcodes.XOR,
            Opcodes.NOT,
            Opcodes.BYTE,
            Opcodes.SHA3,
            Opcodes.ADDRESS,
            Opcodes.BALANCE,
            Opcodes.ORIGIN,
            Opcodes.CALLER,
            Opcodes.CALLVALUE,
            Opcodes.CALLDATALOAD,
            Opcodes.CALLDATASIZE,
            Opcodes.CALLDATACOPY,
            Opcodes.CODESIZE,
            Opcodes.CODECOPY,
            Opcodes.GASPRICE,
            Opcodes.EXTCODESIZE,
            Opcodes.EXTCODECOPY,
            Opcodes.BLOCKHASH,
            Opcodes.COINBASE,
            Opcodes.TIMESTAMP,
            Opcodes.NUMBER,
            Opcodes.PREVRANDAO,
            Opcodes.GASLIMIT,
            Opcodes.POP,
            Opcodes.MLOAD,
            Opcodes.MSTORE,
            Opcodes.MSTORE8,
            Opcodes.SLOAD,
            Opcodes.SSTORE,
            Opcodes.PC,
            Opcodes.MSIZE,
            Opcodes.GAS,
            Opcodes.JUMP,
            Opcodes.JUMPI,
            Opcodes.JUMPDEST,
            Opcodes.PUSH1,
            Opcodes.PUSH2,
            Opcodes.PUSH3,
            Opcodes.PUSH4,
            Opcodes.PUSH5,
            Opcodes.PUSH6,
            Opcodes.PUSH7,
            Opcodes.PUSH8,
            Opcodes.PUSH9,
            Opcodes.PUSH10,
            Opcodes.PUSH11,
            Opcodes.PUSH12,
            Opcodes.PUSH13,
            Opcodes.PUSH14,
            Opcodes.PUSH15,
            Opcodes.PUSH16,
            Opcodes.PUSH17,
            Opcodes.PUSH18,
            Opcodes.PUSH19,
            Opcodes.PUSH20,
            Opcodes.PUSH21,
            Opcodes.PUSH22,
            Opcodes.PUSH23,
            Opcodes.PUSH24,
            Opcodes.PUSH25,
            Opcodes.PUSH26,
            Opcodes.PUSH27,
            Opcodes.PUSH28,
            Opcodes.PUSH29,
            Opcodes.PUSH30,
            Opcodes.PUSH31,
            Opcodes.PUSH32,
            Opcodes.DUP1,
            Opcodes.DUP2,
            Opcodes.DUP3,
            Opcodes.DUP4,
            Opcodes.DUP5,
            Opcodes.DUP6,
            Opcodes.DUP7,
            Opcodes.DUP8,
            Opcodes.DUP9,
            Opcodes.DUP10,
            Opcodes.DUP11,
            Opcodes.DUP12,
            Opcodes.DUP13,
            Opcodes.DUP14,
            Opcodes.DUP15,
            Opcodes.DUP16,
            Opcodes.SWAP1,
            Opcodes.SWAP2,
            Opcodes.SWAP3,
            Opcodes.SWAP4,
            Opcodes.SWAP5,
            Opcodes.SWAP6,
            Opcodes.SWAP7,
            Opcodes.SWAP8,
            Opcodes.SWAP9,
            Opcodes.SWAP10,
            Opcodes.SWAP11,
            Opcodes.SWAP12,
            Opcodes.SWAP13,
            Opcodes.SWAP14,
            Opcodes.SWAP15,
            Opcodes.SWAP16,
            Opcodes.LOG0,
            Opcodes.LOG1,
            Opcodes.LOG2,
            Opcodes.LOG3,
            Opcodes.LOG4,
            Opcodes.CREATE,
            Opcodes.CALL,
            Opcodes.CALLCODE,
            Opcodes.RETURN,
            Opcodes.SELFDESTRUCT,
        ]

    @classmethod
    def create_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """At Genesis, only `CREATE` opcode is supported."""
        del block_number, timestamp
        return [Opcodes.CREATE]

    @classmethod
    def max_refund_quotient(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the max refund quotient at Genesis."""
        del block_number, timestamp
        return 2

    @classmethod
    def max_request_type(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """At genesis, no request type is supported, signaled by -1."""
        del block_number, timestamp
        return -1

    @classmethod
    def pre_allocation(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Mapping:
        """
        Return whether the fork expects pre-allocation of accounts.

        Frontier does not require pre-allocated accounts
        """
        del block_number, timestamp
        return {}

    @classmethod
    def pre_allocation_blockchain(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Mapping:
        """
        Return whether the fork expects pre-allocation of accounts.

        Frontier does not require pre-allocated accounts
        """
        del block_number, timestamp
        return {}

    @classmethod
    def build_default_block_header(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> FixtureHeader:
        """
        Build a default block header for this fork with the given attributes.

        This method automatically detects which header fields are required by
        the fork and assigns appropriate default values. It introspects the
        FixtureHeader model to find fields with HeaderForkRequirement
        annotations and automatically includes them if the fork requires them.

        Args:
            block_number: The block number
            timestamp: The block timestamp

        Returns:
            FixtureHeader instance with default values applied based on fork
            requirements.

        Raises:
            TypeError: If the overrides don't have the correct type.

        """
        from execution_testing.fixtures.blockchain import FixtureHeader

        defaults = {
            "number": ZeroPaddedHexNumber(block_number),
            "timestamp": ZeroPaddedHexNumber(timestamp),
            "fork": cls,
        }

        # Iterate through FixtureHeader fields to populate defaults
        for field_name, field_info in FixtureHeader.model_fields.items():
            if field_name in defaults:
                continue

            # Get default value, checking fork requirements and model defaults
            default_value = FixtureHeader.get_default_from_annotation(
                fork=cls,
                field_name=field_name,
                field_hint=field_info.annotation,
                block_number=int(block_number),
                timestamp=int(timestamp),
            )
            if default_value is not None:
                defaults[field_name] = default_value

        return FixtureHeader(**defaults)

transition_tool_name(*, block_number=0, timestamp=0) classmethod

Return fork name as it's meant to be passed to the transition tool for execution.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
60
61
62
63
64
65
66
67
68
69
70
71
@classmethod
def transition_tool_name(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> str:
    """
    Return fork name as it's meant to be passed to the transition tool for
    execution.
    """
    del block_number, timestamp
    if cls._transition_tool_name is not None:
        return cls._transition_tool_name
    return cls.name()

solc_name() classmethod

Return fork name as it's meant to be passed to the solc compiler.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
73
74
75
76
77
78
@classmethod
def solc_name(cls) -> str:
    """Return fork name as it's meant to be passed to the solc compiler."""
    if cls._solc_name is not None:
        return cls._solc_name
    return cls.name().lower()

header_base_fee_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not contain base fee.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
80
81
82
83
84
85
86
@classmethod
def header_base_fee_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not contain base fee."""
    del block_number, timestamp
    return False

header_prev_randao_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not contain Prev Randao value.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
88
89
90
91
92
93
94
@classmethod
def header_prev_randao_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not contain Prev Randao value."""
    del block_number, timestamp
    return False

header_zero_difficulty_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not have difficulty zero.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
 96
 97
 98
 99
100
101
102
@classmethod
def header_zero_difficulty_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not have difficulty zero."""
    del block_number, timestamp
    return False

header_withdrawals_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not contain withdrawals.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
104
105
106
107
108
109
110
@classmethod
def header_withdrawals_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not contain withdrawals."""
    del block_number, timestamp
    return False

header_excess_blob_gas_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not contain excess blob gas.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
112
113
114
115
116
117
118
@classmethod
def header_excess_blob_gas_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not contain excess blob gas."""
    del block_number, timestamp
    return False

header_blob_gas_used_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not contain blob gas used.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
120
121
122
123
124
125
126
@classmethod
def header_blob_gas_used_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not contain blob gas used."""
    del block_number, timestamp
    return False

gas_costs(*, block_number=0, timestamp=0) classmethod

Return dataclass with the defined gas costs constants for genesis.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
@classmethod
def gas_costs(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> GasCosts:
    """
    Return dataclass with the defined gas costs constants for genesis.
    """
    del block_number, timestamp
    return GasCosts(
        G_JUMPDEST=1,
        G_BASE=2,
        G_VERY_LOW=3,
        G_LOW=5,
        G_MID=8,
        G_HIGH=10,
        G_WARM_ACCOUNT_ACCESS=100,
        G_COLD_ACCOUNT_ACCESS=2_600,
        G_ACCESS_LIST_ADDRESS=2_400,
        G_ACCESS_LIST_STORAGE=1_900,
        G_WARM_SLOAD=100,
        G_COLD_SLOAD=2_100,
        G_STORAGE_SET=20_000,
        G_STORAGE_UPDATE=5_000,
        G_STORAGE_RESET=2_900,
        R_STORAGE_CLEAR=4_800,
        G_SELF_DESTRUCT=5_000,
        G_CREATE=32_000,
        G_CODE_DEPOSIT_BYTE=200,
        G_INITCODE_WORD=2,
        G_CALL_VALUE=9_000,
        G_CALL_STIPEND=2_300,
        G_NEW_ACCOUNT=25_000,
        G_EXP=10,
        G_EXP_BYTE=50,
        G_MEMORY=3,
        G_TX_DATA_ZERO=4,
        G_TX_DATA_NON_ZERO=68,
        G_TRANSACTION=21_000,
        G_TRANSACTION_CREATE=32_000,
        G_LOG=375,
        G_LOG_DATA=8,
        G_LOG_TOPIC=375,
        G_KECCAK_256=30,
        G_KECCAK_256_WORD=6,
        G_COPY=3,
        G_BLOCKHASH=20,
        G_PRECOMPILE_ECRECOVER=3_000,
        G_PRECOMPILE_SHA256_BASE=60,
        G_PRECOMPILE_SHA256_WORD=12,
        G_PRECOMPILE_RIPEMD160_BASE=600,
        G_PRECOMPILE_RIPEMD160_WORD=120,
        G_PRECOMPILE_IDENTITY_BASE=15,
        G_PRECOMPILE_IDENTITY_WORD=3,
        # Zero-initialized: introduced in later forks, set via
        # replace() in the fork that activates them.
        G_TX_DATA_STANDARD_TOKEN_COST=0,
        G_TX_DATA_FLOOR_TOKEN_COST=0,
        G_AUTHORIZATION=0,
        R_AUTHORIZATION_EXISTING_AUTHORITY=0,
        G_PRECOMPILE_ECADD=0,
        G_PRECOMPILE_ECMUL=0,
        G_PRECOMPILE_ECPAIRING_BASE=0,
        G_PRECOMPILE_ECPAIRING_PER_POINT=0,
        G_PRECOMPILE_BLAKE2F_BASE=0,
        G_PRECOMPILE_BLAKE2F_PER_ROUND=0,
        G_PRECOMPILE_POINT_EVALUATION=0,
        G_PRECOMPILE_BLS_G1ADD=0,
        G_PRECOMPILE_BLS_G1MUL=0,
        G_PRECOMPILE_BLS_G1MAP=0,
        G_PRECOMPILE_BLS_G2ADD=0,
        G_PRECOMPILE_BLS_G2MUL=0,
        G_PRECOMPILE_BLS_G2MAP=0,
        G_PRECOMPILE_BLS_PAIRING_BASE=0,
        G_PRECOMPILE_BLS_PAIRING_PER_PAIR=0,
        G_PRECOMPILE_P256VERIFY=0,
    )

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Return a mapping of opcodes to their gas costs.

Each entry is either: - Constants (int): Direct gas cost values from gas_costs() - Callables: Functions that take the opcode instance with metadata and return gas cost

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """
    Return a mapping of opcodes to their gas costs.

    Each entry is either:
    - Constants (int): Direct gas cost values from gas_costs()
    - Callables: Functions that take the opcode instance with metadata and
                 return gas cost
    """
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    memory_expansion_calculator = cls.memory_expansion_gas_calculator(
        block_number=block_number, timestamp=timestamp
    )

    # Define the opcode gas cost mapping
    # Each entry is either:
    # - an int (constant cost)
    # - a callable(opcode) -> int
    return {
        # Stop and arithmetic operations
        Opcodes.STOP: 0,
        Opcodes.ADD: gas_costs.G_VERY_LOW,
        Opcodes.MUL: gas_costs.G_LOW,
        Opcodes.SUB: gas_costs.G_VERY_LOW,
        Opcodes.DIV: gas_costs.G_LOW,
        Opcodes.SDIV: gas_costs.G_LOW,
        Opcodes.MOD: gas_costs.G_LOW,
        Opcodes.SMOD: gas_costs.G_LOW,
        Opcodes.ADDMOD: gas_costs.G_MID,
        Opcodes.MULMOD: gas_costs.G_MID,
        Opcodes.EXP: lambda op: (
            gas_costs.G_EXP
            + gas_costs.G_EXP_BYTE
            * ((op.metadata["exponent"].bit_length() + 7) // 8)
        ),
        Opcodes.SIGNEXTEND: gas_costs.G_LOW,
        # Comparison & bitwise logic operations
        Opcodes.LT: gas_costs.G_VERY_LOW,
        Opcodes.GT: gas_costs.G_VERY_LOW,
        Opcodes.SLT: gas_costs.G_VERY_LOW,
        Opcodes.SGT: gas_costs.G_VERY_LOW,
        Opcodes.EQ: gas_costs.G_VERY_LOW,
        Opcodes.ISZERO: gas_costs.G_VERY_LOW,
        Opcodes.AND: gas_costs.G_VERY_LOW,
        Opcodes.OR: gas_costs.G_VERY_LOW,
        Opcodes.XOR: gas_costs.G_VERY_LOW,
        Opcodes.NOT: gas_costs.G_VERY_LOW,
        Opcodes.BYTE: gas_costs.G_VERY_LOW,
        # SHA3
        Opcodes.SHA3: cls._with_memory_expansion(
            lambda op: (
                gas_costs.G_KECCAK_256
                + gas_costs.G_KECCAK_256_WORD
                * ((op.metadata["data_size"] + 31) // 32)
            ),
            memory_expansion_calculator,
        ),
        # Environmental information
        Opcodes.ADDRESS: gas_costs.G_BASE,
        Opcodes.BALANCE: cls._with_account_access(0, gas_costs),
        Opcodes.ORIGIN: gas_costs.G_BASE,
        Opcodes.CALLER: gas_costs.G_BASE,
        Opcodes.CALLVALUE: gas_costs.G_BASE,
        Opcodes.CALLDATALOAD: gas_costs.G_VERY_LOW,
        Opcodes.CALLDATASIZE: gas_costs.G_BASE,
        Opcodes.CALLDATACOPY: cls._with_memory_expansion(
            cls._with_data_copy(gas_costs.G_VERY_LOW, gas_costs),
            memory_expansion_calculator,
        ),
        Opcodes.CODESIZE: gas_costs.G_BASE,
        Opcodes.CODECOPY: cls._with_memory_expansion(
            cls._with_data_copy(gas_costs.G_VERY_LOW, gas_costs),
            memory_expansion_calculator,
        ),
        Opcodes.GASPRICE: gas_costs.G_BASE,
        Opcodes.EXTCODESIZE: cls._with_account_access(0, gas_costs),
        Opcodes.EXTCODECOPY: cls._with_memory_expansion(
            cls._with_data_copy(
                cls._with_account_access(0, gas_costs),
                gas_costs,
            ),
            memory_expansion_calculator,
        ),
        # Block information
        Opcodes.BLOCKHASH: gas_costs.G_BLOCKHASH,
        Opcodes.COINBASE: gas_costs.G_BASE,
        Opcodes.TIMESTAMP: gas_costs.G_BASE,
        Opcodes.NUMBER: gas_costs.G_BASE,
        Opcodes.PREVRANDAO: gas_costs.G_BASE,
        Opcodes.GASLIMIT: gas_costs.G_BASE,
        # Stack, memory, storage and flow operations
        Opcodes.POP: gas_costs.G_BASE,
        Opcodes.MLOAD: cls._with_memory_expansion(
            gas_costs.G_VERY_LOW, memory_expansion_calculator
        ),
        Opcodes.MSTORE: cls._with_memory_expansion(
            gas_costs.G_VERY_LOW, memory_expansion_calculator
        ),
        Opcodes.MSTORE8: cls._with_memory_expansion(
            gas_costs.G_VERY_LOW, memory_expansion_calculator
        ),
        Opcodes.SLOAD: lambda op: (
            gas_costs.G_WARM_SLOAD
            if op.metadata["key_warm"]
            else gas_costs.G_COLD_SLOAD
        ),
        Opcodes.SSTORE: lambda op: cls._calculate_sstore_gas(
            op, gas_costs
        ),
        Opcodes.JUMP: gas_costs.G_MID,
        Opcodes.JUMPI: gas_costs.G_HIGH,
        Opcodes.PC: gas_costs.G_BASE,
        Opcodes.MSIZE: gas_costs.G_BASE,
        Opcodes.GAS: gas_costs.G_BASE,
        Opcodes.JUMPDEST: gas_costs.G_JUMPDEST,
        # Push operations (PUSH1 through PUSH32)
        **{
            getattr(Opcodes, f"PUSH{i}"): gas_costs.G_VERY_LOW
            for i in range(1, 33)
        },
        # Dup operations (DUP1 through DUP16)
        **{
            getattr(Opcodes, f"DUP{i}"): gas_costs.G_VERY_LOW
            for i in range(1, 17)
        },
        # Swap operations (SWAP1 through SWAP16)
        **{
            getattr(Opcodes, f"SWAP{i}"): gas_costs.G_VERY_LOW
            for i in range(1, 17)
        },
        # Logging operations
        Opcodes.LOG0: cls._with_memory_expansion(
            lambda op: (
                gas_costs.G_LOG
                + gas_costs.G_LOG_DATA * op.metadata["data_size"]
            ),
            memory_expansion_calculator,
        ),
        Opcodes.LOG1: cls._with_memory_expansion(
            lambda op: (
                gas_costs.G_LOG
                + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                + gas_costs.G_LOG_TOPIC
            ),
            memory_expansion_calculator,
        ),
        Opcodes.LOG2: cls._with_memory_expansion(
            lambda op: (
                gas_costs.G_LOG
                + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                + gas_costs.G_LOG_TOPIC * 2
            ),
            memory_expansion_calculator,
        ),
        Opcodes.LOG3: cls._with_memory_expansion(
            lambda op: (
                gas_costs.G_LOG
                + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                + gas_costs.G_LOG_TOPIC * 3
            ),
            memory_expansion_calculator,
        ),
        Opcodes.LOG4: cls._with_memory_expansion(
            lambda op: (
                gas_costs.G_LOG
                + gas_costs.G_LOG_DATA * op.metadata["data_size"]
                + gas_costs.G_LOG_TOPIC * 4
            ),
            memory_expansion_calculator,
        ),
        # System operations
        Opcodes.CREATE: cls._with_memory_expansion(
            lambda op: cls._calculate_create_gas(op, gas_costs),
            memory_expansion_calculator,
        ),
        Opcodes.CALL: cls._with_memory_expansion(
            lambda op: cls._calculate_call_gas(op, gas_costs),
            memory_expansion_calculator,
        ),
        Opcodes.CALLCODE: cls._with_memory_expansion(
            lambda op: cls._calculate_call_gas(op, gas_costs),
            memory_expansion_calculator,
        ),
        Opcodes.RETURN: cls._with_memory_expansion(
            lambda op: cls._calculate_return_gas(op, gas_costs),
            memory_expansion_calculator,
        ),
        Opcodes.INVALID: 0,
        Opcodes.SELFDESTRUCT: lambda op: cls._calculate_selfdestruct_gas(
            op, gas_costs
        ),
    }

opcode_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return callable that calculates the gas cost of a single opcode.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
@classmethod
def opcode_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> OpcodeGasCalculator:
    """
    Return callable that calculates the gas cost of a single opcode.
    """
    opcode_gas_map = cls.opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )

    def fn(opcode: OpcodeBase) -> int:
        # Get the gas cost or calculator
        if opcode not in opcode_gas_map:
            raise ValueError(
                f"No gas cost defined for opcode: {opcode._name_}"
            )
        gas_cost_or_calculator = opcode_gas_map[opcode]

        # If it's a callable, call it with the opcode
        if callable(gas_cost_or_calculator):
            return gas_cost_or_calculator(opcode)

        # Otherwise it's a constant
        return gas_cost_or_calculator

    return fn

opcode_refund_map(*, block_number=0, timestamp=0) classmethod

Return a mapping of opcodes to their gas refunds.

Each entry is either: - Constants (int): Direct gas refund values - Callables: Functions that take the opcode instance with metadata and return gas refund

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
@classmethod
def opcode_refund_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """
    Return a mapping of opcodes to their gas refunds.

    Each entry is either:
    - Constants (int): Direct gas refund values
    - Callables: Functions that take the opcode instance with metadata and
                 return gas refund
    """
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )

    # Only SSTORE provides refunds
    return {
        Opcodes.SSTORE: lambda op: cls._calculate_sstore_refund(
            op, gas_costs
        ),
    }

opcode_refund_calculator(*, block_number=0, timestamp=0) classmethod

Return callable that calculates the gas refund of a single opcode.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
@classmethod
def opcode_refund_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> OpcodeGasCalculator:
    """
    Return callable that calculates the gas refund of a single opcode.
    """
    opcode_refund_map = cls.opcode_refund_map(
        block_number=block_number, timestamp=timestamp
    )

    def fn(opcode: OpcodeBase) -> int:
        # Get the gas refund or calculator
        if opcode not in opcode_refund_map:
            # Most opcodes don't provide refunds
            return 0
        refund_or_calculator = opcode_refund_map[opcode]

        # If it's a callable, call it with the opcode
        if callable(refund_or_calculator):
            return refund_or_calculator(opcode)

        # Otherwise it's a constant
        return refund_or_calculator

    return fn

memory_expansion_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return callable that calculates the gas cost of memory expansion for the fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
@classmethod
def memory_expansion_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> MemoryExpansionGasCalculator:
    """
    Return callable that calculates the gas cost of memory expansion for
    the fork.
    """
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )

    def fn(*, new_bytes: int, previous_bytes: int = 0) -> int:
        if new_bytes <= previous_bytes:
            return 0
        new_words = ceiling_division(new_bytes, 32)
        previous_words = ceiling_division(previous_bytes, 32)

        def c(w: int) -> int:
            return (gas_costs.G_MEMORY * w) + ((w * w) // 512)

        return c(new_words) - c(previous_words)

    return fn

calldata_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return callable that calculates the transaction gas cost for its calldata depending on its contents.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
@classmethod
def calldata_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> CalldataGasCalculator:
    """
    Return callable that calculates the transaction gas cost for its
    calldata depending on its contents.
    """
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )

    def fn(*, data: BytesConvertible, floor: bool = False) -> int:
        del floor

        cost = 0
        for b in Bytes(data):
            if b == 0:
                cost += gas_costs.G_TX_DATA_ZERO
            else:
                cost += gas_costs.G_TX_DATA_NON_ZERO
        return cost

    return fn

base_fee_per_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the base fee per gas at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
759
760
761
762
763
764
765
766
767
768
@classmethod
def base_fee_per_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> BaseFeePerGasCalculator:
    """
    Return a callable that calculates the base fee per gas at a given fork.
    """
    raise NotImplementedError(
        f"Base fee per gas calculator is not supported in {cls.name()}"
    )

base_fee_change_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the gas that needs to be used to change the base fee.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
770
771
772
773
774
775
776
777
778
779
780
@classmethod
def base_fee_change_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> BaseFeeChangeCalculator:
    """
    Return a callable that calculates the gas that needs to be used to
    change the base fee.
    """
    raise NotImplementedError(
        f"Base fee change calculator is not supported in {cls.name()}"
    )

base_fee_max_change_denominator(*, block_number=0, timestamp=0) classmethod

Return the base fee max change denominator at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
782
783
784
785
786
787
788
789
790
@classmethod
def base_fee_max_change_denominator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the base fee max change denominator at a given fork."""
    del block_number, timestamp
    raise NotImplementedError(
        f"Base fee max change denominator is not supported in {cls.name()}"
    )

base_fee_elasticity_multiplier(*, block_number=0, timestamp=0) classmethod

Return the base fee elasticity multiplier at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
792
793
794
795
796
797
798
799
800
@classmethod
def base_fee_elasticity_multiplier(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the base fee elasticity multiplier at a given fork."""
    del block_number, timestamp
    raise NotImplementedError(
        f"Base fee elasticity multiplier is not supported in {cls.name()}"
    )

transaction_data_floor_cost_calculator(*, block_number=0, timestamp=0) classmethod

At frontier, the transaction data floor cost is a constant zero.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
802
803
804
805
806
807
808
809
810
811
812
813
@classmethod
def transaction_data_floor_cost_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> TransactionDataFloorCostCalculator:
    """At frontier, the transaction data floor cost is a constant zero."""
    del block_number, timestamp

    def fn(*, data: BytesConvertible) -> int:
        del data
        return 0

    return fn

transaction_intrinsic_cost_calculator(*, block_number=0, timestamp=0) classmethod

Return callable that calculates the intrinsic gas cost of a transaction for the fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
@classmethod
def transaction_intrinsic_cost_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> TransactionIntrinsicCostCalculator:
    """
    Return callable that calculates the intrinsic gas cost of a transaction
    for the fork.
    """
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    calldata_gas_calculator = cls.calldata_gas_calculator(
        block_number=block_number, timestamp=timestamp
    )

    def fn(
        *,
        calldata: BytesConvertible = b"",
        contract_creation: bool = False,
        access_list: List[AccessList] | None = None,
        authorization_list_or_count: Sized | int | None = None,
        return_cost_deducted_prior_execution: bool = False,
    ) -> int:
        del return_cost_deducted_prior_execution

        assert access_list is None, (
            f"Access list is not supported in {cls.name()}"
        )
        assert authorization_list_or_count is None, (
            f"Authorizations are not supported in {cls.name()}"
        )

        intrinsic_cost: int = gas_costs.G_TRANSACTION

        if contract_creation:
            intrinsic_cost += gas_costs.G_INITCODE_WORD * ceiling_division(
                len(Bytes(calldata)), 32
            )

        return intrinsic_cost + calldata_gas_calculator(data=calldata)

    return fn

blob_gas_price_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the blob gas price at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
858
859
860
861
862
863
864
865
866
867
@classmethod
def blob_gas_price_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> BlobGasPriceCalculator:
    """
    Return a callable that calculates the blob gas price at a given fork.
    """
    raise NotImplementedError(
        f"Blob gas price calculator is not supported in {cls.name()}"
    )

excess_blob_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the excess blob gas for a block at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
869
870
871
872
873
874
875
876
877
878
879
@classmethod
def excess_blob_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> ExcessBlobGasCalculator:
    """
    Return a callable that calculates the excess blob gas for a block at a
    given fork.
    """
    raise NotImplementedError(
        f"Excess blob gas calculator is not supported in {cls.name()}"
    )

min_base_fee_per_blob_gas(*, block_number=0, timestamp=0) classmethod

Return the amount of blob gas used per blob at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
881
882
883
884
885
886
887
888
889
@classmethod
def min_base_fee_per_blob_gas(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the amount of blob gas used per blob at a given fork."""
    del block_number, timestamp
    raise NotImplementedError(
        f"Base fee per blob gas is not supported in {cls.name()}"
    )

blob_base_fee_update_fraction(*, block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
891
892
893
894
895
896
897
898
899
@classmethod
def blob_base_fee_update_fraction(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the blob base fee update fraction at a given fork."""
    del block_number, timestamp
    raise NotImplementedError(
        f"Blob base fee update fraction is not supported in {cls.name()}"
    )

blob_gas_per_blob(*, block_number=0, timestamp=0) classmethod

Return the amount of blob gas used per blob at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
901
902
903
904
905
906
907
@classmethod
def blob_gas_per_blob(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the amount of blob gas used per blob at a given fork."""
    del block_number, timestamp
    return 0

supports_blobs(*, block_number=0, timestamp=0) classmethod

Blobs are not supported at Frontier.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
909
910
911
912
913
914
915
@classmethod
def supports_blobs(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Blobs are not supported at Frontier."""
    del block_number, timestamp
    return False

target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Return the target number of blobs per block at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
917
918
919
920
921
922
923
924
925
@classmethod
def target_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the target number of blobs per block at a given fork."""
    del block_number, timestamp
    raise NotImplementedError(
        f"Target blobs per block is not supported in {cls.name()}"
    )

max_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Return the max number of blobs per block at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
927
928
929
930
931
932
933
934
935
@classmethod
def max_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the max number of blobs per block at a given fork."""
    del block_number, timestamp
    raise NotImplementedError(
        f"Max blobs per block is not supported in {cls.name()}"
    )

blob_reserve_price_active(*, block_number=0, timestamp=0) classmethod

Return whether the fork uses a reserve price mechanism for blobs or not.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
937
938
939
940
941
942
943
944
945
946
947
948
@classmethod
def blob_reserve_price_active(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """
    Return whether the fork uses a reserve price mechanism for blobs or
    not.
    """
    del block_number, timestamp
    raise NotImplementedError(
        f"Blob reserve price is not supported in {cls.name()}"
    )

blob_base_cost(*, block_number=0, timestamp=0) classmethod

Return the base cost of a blob at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
950
951
952
953
954
955
956
957
958
@classmethod
def blob_base_cost(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the base cost of a blob at a given fork."""
    del block_number, timestamp
    raise NotImplementedError(
        f"Blob base cost is not supported in {cls.name()}"
    )

full_blob_tx_wrapper_version(*, block_number=0, timestamp=0) classmethod

Return the version of the full blob transaction wrapper.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
960
961
962
963
964
965
966
967
968
@classmethod
def full_blob_tx_wrapper_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int | None:
    """Return the version of the full blob transaction wrapper."""
    raise NotImplementedError(
        "Full blob transaction wrapper version is not supported in "
        f"{cls.name()}"
    )

max_blobs_per_tx(*, block_number=0, timestamp=0) classmethod

Return the max number of blobs per tx at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
970
971
972
973
974
975
976
977
978
@classmethod
def max_blobs_per_tx(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the max number of blobs per tx at a given fork."""
    del block_number, timestamp
    raise NotImplementedError(
        f"Max blobs per tx is not supported in {cls.name()}"
    )

blob_schedule(*, block_number=0, timestamp=0) classmethod

At genesis, no blob schedule is used.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
980
981
982
983
984
985
986
@classmethod
def blob_schedule(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> BlobSchedule | None:
    """At genesis, no blob schedule is used."""
    del block_number, timestamp
    return None

header_requests_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not contain beacon chain requests.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
988
989
990
991
992
993
994
@classmethod
def header_requests_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not contain beacon chain requests."""
    del block_number, timestamp
    return False

header_bal_hash_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not contain block access list hash.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
 996
 997
 998
 999
1000
1001
1002
@classmethod
def header_bal_hash_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not contain block access list hash."""
    del block_number, timestamp
    return False

engine_new_payload_version(*, block_number=0, timestamp=0) classmethod

At genesis, payloads cannot be sent through the engine API.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1004
1005
1006
1007
1008
1009
1010
@classmethod
def engine_new_payload_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """At genesis, payloads cannot be sent through the engine API."""
    del block_number, timestamp
    return None

header_beacon_root_required(*, block_number=0, timestamp=0) classmethod

At genesis, header must not contain parent beacon block root.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1012
1013
1014
1015
1016
1017
1018
@classmethod
def header_beacon_root_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, header must not contain parent beacon block root."""
    del block_number, timestamp
    return False

engine_new_payload_blob_hashes(*, block_number=0, timestamp=0) classmethod

At genesis, payloads do not have blob hashes.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1020
1021
1022
1023
1024
1025
1026
@classmethod
def engine_new_payload_blob_hashes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, payloads do not have blob hashes."""
    del block_number, timestamp
    return False

engine_new_payload_beacon_root(*, block_number=0, timestamp=0) classmethod

At genesis, payloads do not have a parent beacon block root.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1028
1029
1030
1031
1032
1033
1034
@classmethod
def engine_new_payload_beacon_root(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, payloads do not have a parent beacon block root."""
    del block_number, timestamp
    return False

engine_new_payload_requests(*, block_number=0, timestamp=0) classmethod

At genesis, payloads do not have requests.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1036
1037
1038
1039
1040
1041
1042
@classmethod
def engine_new_payload_requests(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, payloads do not have requests."""
    del block_number, timestamp
    return False

engine_execution_payload_block_access_list(*, block_number=0, timestamp=0) classmethod

At genesis, payloads do not have block access list.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1044
1045
1046
1047
1048
1049
1050
@classmethod
def engine_execution_payload_block_access_list(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """At genesis, payloads do not have block access list."""
    del block_number, timestamp
    return False

engine_new_payload_target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

At genesis, payloads do not have target blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
@classmethod
def engine_new_payload_target_blobs_per_block(
    cls,
    *,
    block_number: int = 0,
    timestamp: int = 0,
) -> bool:
    """At genesis, payloads do not have target blobs per block."""
    del block_number, timestamp
    return False

engine_payload_attribute_target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

At genesis, payload attributes do not include the target blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
@classmethod
def engine_payload_attribute_target_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """
    At genesis, payload attributes do not include the target blobs per
    block.
    """
    del block_number, timestamp
    return False

engine_payload_attribute_max_blobs_per_block(*, block_number=0, timestamp=0) classmethod

At genesis, payload attributes do not include the max blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1074
1075
1076
1077
1078
1079
1080
1081
1082
@classmethod
def engine_payload_attribute_max_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """
    At genesis, payload attributes do not include the max blobs per block.
    """
    del block_number, timestamp
    return False

engine_forkchoice_updated_version(*, block_number=0, timestamp=0) classmethod

At genesis, forkchoice updates cannot be sent through the engine API.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
@classmethod
def engine_forkchoice_updated_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """
    At genesis, forkchoice updates cannot be sent through the engine API.
    """
    return cls.engine_new_payload_version(
        block_number=block_number, timestamp=timestamp
    )

engine_get_payload_version(*, block_number=0, timestamp=0) classmethod

At genesis, payloads cannot be retrieved through the engine API.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1095
1096
1097
1098
1099
1100
1101
1102
@classmethod
def engine_get_payload_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """At genesis, payloads cannot be retrieved through the engine API."""
    return cls.engine_new_payload_version(
        block_number=block_number, timestamp=timestamp
    )

engine_get_blobs_version(*, block_number=0, timestamp=0) classmethod

At genesis, blobs cannot be retrieved through the engine API.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1104
1105
1106
1107
1108
1109
1110
@classmethod
def engine_get_blobs_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """At genesis, blobs cannot be retrieved through the engine API."""
    del block_number, timestamp
    return None

get_reward(*, block_number=0, timestamp=0) classmethod

At Genesis the expected reward amount in wei is 5_000_000_000_000_000_000.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1112
1113
1114
1115
1116
1117
1118
1119
@classmethod
def get_reward(cls, *, block_number: int = 0, timestamp: int = 0) -> int:
    """
    At Genesis the expected reward amount in wei is
    5_000_000_000_000_000_000.
    """
    del block_number, timestamp
    return 5_000_000_000_000_000_000

supports_protected_txs() classmethod

At Genesis, fork has no support for EIP-155 protected txs.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1121
1122
1123
1124
@classmethod
def supports_protected_txs(cls) -> bool:
    """At Genesis, fork has no support for EIP-155 protected txs."""
    return False

tx_types(*, block_number=0, timestamp=0) classmethod

At Genesis, only legacy transactions are allowed.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1126
1127
1128
1129
1130
1131
1132
@classmethod
def tx_types(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[int]:
    """At Genesis, only legacy transactions are allowed."""
    del block_number, timestamp
    return [0]

contract_creating_tx_types(*, block_number=0, timestamp=0) classmethod

At Genesis, only legacy transactions are allowed.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1134
1135
1136
1137
1138
1139
1140
@classmethod
def contract_creating_tx_types(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[int]:
    """At Genesis, only legacy transactions are allowed."""
    del block_number, timestamp
    return [0]

transaction_gas_limit_cap(*, block_number=0, timestamp=0) classmethod

At Genesis, no transaction gas limit cap is imposed.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1142
1143
1144
1145
1146
1147
1148
@classmethod
def transaction_gas_limit_cap(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int | None:
    """At Genesis, no transaction gas limit cap is imposed."""
    del block_number, timestamp
    return None

block_rlp_size_limit(*, block_number=0, timestamp=0) classmethod

At Genesis, no RLP block size limit is imposed.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1150
1151
1152
1153
1154
1155
1156
@classmethod
def block_rlp_size_limit(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int | None:
    """At Genesis, no RLP block size limit is imposed."""
    del block_number, timestamp
    return None

precompiles(*, block_number=0, timestamp=0) classmethod

At Genesis, no precompiles are present.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1158
1159
1160
1161
1162
1163
1164
@classmethod
def precompiles(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """At Genesis, no precompiles are present."""
    del block_number, timestamp
    return []

system_contracts(*, block_number=0, timestamp=0) classmethod

At Genesis, no system contracts are present.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1166
1167
1168
1169
1170
1171
1172
@classmethod
def system_contracts(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """At Genesis, no system contracts are present."""
    del block_number, timestamp
    return []

deterministic_factory_predeploy_address(*, block_number=0, timestamp=0) classmethod

At Genesis, no deterministic factory predeploy is present.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1174
1175
1176
1177
1178
1179
1180
@classmethod
def deterministic_factory_predeploy_address(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Address | None:
    """At Genesis, no deterministic factory predeploy is present."""
    del block_number, timestamp
    return None

max_code_size(*, block_number=0, timestamp=0) classmethod

At genesis, there is no upper bound for code size (bounded by block gas limit).

However, the default is set to the limit of EIP-170 (Spurious Dragon)

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
@classmethod
def max_code_size(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """
    At genesis, there is no upper bound for code size (bounded by block gas
    limit).

    However, the default is set to the limit of EIP-170 (Spurious Dragon)
    """
    del block_number, timestamp
    return 0x6000

max_stack_height(*, block_number=0, timestamp=0) classmethod

At genesis, the maximum stack height is 1024.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1195
1196
1197
1198
1199
1200
1201
@classmethod
def max_stack_height(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """At genesis, the maximum stack height is 1024."""
    del block_number, timestamp
    return 1024

max_initcode_size(*, block_number=0, timestamp=0) classmethod

At genesis, there is no upper bound for initcode size.

However, the default is set to the limit of EIP-3860 (Shanghai).

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
@classmethod
def max_initcode_size(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """
    At genesis, there is no upper bound for initcode size.

    However, the default is set to the limit of EIP-3860 (Shanghai).
    """
    del block_number, timestamp
    return 0xC000

call_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of call opcodes supported by the fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1215
1216
1217
1218
1219
1220
1221
@classmethod
def call_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of call opcodes supported by the fork."""
    del block_number, timestamp
    return [Opcodes.CALL, Opcodes.CALLCODE]

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [
        Opcodes.STOP,
        Opcodes.ADD,
        Opcodes.MUL,
        Opcodes.SUB,
        Opcodes.DIV,
        Opcodes.SDIV,
        Opcodes.MOD,
        Opcodes.SMOD,
        Opcodes.ADDMOD,
        Opcodes.MULMOD,
        Opcodes.EXP,
        Opcodes.SIGNEXTEND,
        Opcodes.LT,
        Opcodes.GT,
        Opcodes.SLT,
        Opcodes.SGT,
        Opcodes.EQ,
        Opcodes.ISZERO,
        Opcodes.AND,
        Opcodes.OR,
        Opcodes.XOR,
        Opcodes.NOT,
        Opcodes.BYTE,
        Opcodes.SHA3,
        Opcodes.ADDRESS,
        Opcodes.BALANCE,
        Opcodes.ORIGIN,
        Opcodes.CALLER,
        Opcodes.CALLVALUE,
        Opcodes.CALLDATALOAD,
        Opcodes.CALLDATASIZE,
        Opcodes.CALLDATACOPY,
        Opcodes.CODESIZE,
        Opcodes.CODECOPY,
        Opcodes.GASPRICE,
        Opcodes.EXTCODESIZE,
        Opcodes.EXTCODECOPY,
        Opcodes.BLOCKHASH,
        Opcodes.COINBASE,
        Opcodes.TIMESTAMP,
        Opcodes.NUMBER,
        Opcodes.PREVRANDAO,
        Opcodes.GASLIMIT,
        Opcodes.POP,
        Opcodes.MLOAD,
        Opcodes.MSTORE,
        Opcodes.MSTORE8,
        Opcodes.SLOAD,
        Opcodes.SSTORE,
        Opcodes.PC,
        Opcodes.MSIZE,
        Opcodes.GAS,
        Opcodes.JUMP,
        Opcodes.JUMPI,
        Opcodes.JUMPDEST,
        Opcodes.PUSH1,
        Opcodes.PUSH2,
        Opcodes.PUSH3,
        Opcodes.PUSH4,
        Opcodes.PUSH5,
        Opcodes.PUSH6,
        Opcodes.PUSH7,
        Opcodes.PUSH8,
        Opcodes.PUSH9,
        Opcodes.PUSH10,
        Opcodes.PUSH11,
        Opcodes.PUSH12,
        Opcodes.PUSH13,
        Opcodes.PUSH14,
        Opcodes.PUSH15,
        Opcodes.PUSH16,
        Opcodes.PUSH17,
        Opcodes.PUSH18,
        Opcodes.PUSH19,
        Opcodes.PUSH20,
        Opcodes.PUSH21,
        Opcodes.PUSH22,
        Opcodes.PUSH23,
        Opcodes.PUSH24,
        Opcodes.PUSH25,
        Opcodes.PUSH26,
        Opcodes.PUSH27,
        Opcodes.PUSH28,
        Opcodes.PUSH29,
        Opcodes.PUSH30,
        Opcodes.PUSH31,
        Opcodes.PUSH32,
        Opcodes.DUP1,
        Opcodes.DUP2,
        Opcodes.DUP3,
        Opcodes.DUP4,
        Opcodes.DUP5,
        Opcodes.DUP6,
        Opcodes.DUP7,
        Opcodes.DUP8,
        Opcodes.DUP9,
        Opcodes.DUP10,
        Opcodes.DUP11,
        Opcodes.DUP12,
        Opcodes.DUP13,
        Opcodes.DUP14,
        Opcodes.DUP15,
        Opcodes.DUP16,
        Opcodes.SWAP1,
        Opcodes.SWAP2,
        Opcodes.SWAP3,
        Opcodes.SWAP4,
        Opcodes.SWAP5,
        Opcodes.SWAP6,
        Opcodes.SWAP7,
        Opcodes.SWAP8,
        Opcodes.SWAP9,
        Opcodes.SWAP10,
        Opcodes.SWAP11,
        Opcodes.SWAP12,
        Opcodes.SWAP13,
        Opcodes.SWAP14,
        Opcodes.SWAP15,
        Opcodes.SWAP16,
        Opcodes.LOG0,
        Opcodes.LOG1,
        Opcodes.LOG2,
        Opcodes.LOG3,
        Opcodes.LOG4,
        Opcodes.CREATE,
        Opcodes.CALL,
        Opcodes.CALLCODE,
        Opcodes.RETURN,
        Opcodes.SELFDESTRUCT,
    ]

create_opcodes(*, block_number=0, timestamp=0) classmethod

At Genesis, only CREATE opcode is supported.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1361
1362
1363
1364
1365
1366
1367
@classmethod
def create_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """At Genesis, only `CREATE` opcode is supported."""
    del block_number, timestamp
    return [Opcodes.CREATE]

max_refund_quotient(*, block_number=0, timestamp=0) classmethod

Return the max refund quotient at Genesis.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1369
1370
1371
1372
1373
1374
1375
@classmethod
def max_refund_quotient(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the max refund quotient at Genesis."""
    del block_number, timestamp
    return 2

max_request_type(*, block_number=0, timestamp=0) classmethod

At genesis, no request type is supported, signaled by -1.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1377
1378
1379
1380
1381
1382
1383
@classmethod
def max_request_type(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """At genesis, no request type is supported, signaled by -1."""
    del block_number, timestamp
    return -1

pre_allocation(*, block_number=0, timestamp=0) classmethod

Return whether the fork expects pre-allocation of accounts.

Frontier does not require pre-allocated accounts

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
@classmethod
def pre_allocation(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Mapping:
    """
    Return whether the fork expects pre-allocation of accounts.

    Frontier does not require pre-allocated accounts
    """
    del block_number, timestamp
    return {}

pre_allocation_blockchain(*, block_number=0, timestamp=0) classmethod

Return whether the fork expects pre-allocation of accounts.

Frontier does not require pre-allocated accounts

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
@classmethod
def pre_allocation_blockchain(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Mapping:
    """
    Return whether the fork expects pre-allocation of accounts.

    Frontier does not require pre-allocated accounts
    """
    del block_number, timestamp
    return {}

build_default_block_header(*, block_number=0, timestamp=0) classmethod

Build a default block header for this fork with the given attributes.

This method automatically detects which header fields are required by the fork and assigns appropriate default values. It introspects the FixtureHeader model to find fields with HeaderForkRequirement annotations and automatically includes them if the fork requires them.

Parameters:

Name Type Description Default
block_number int

The block number

0
timestamp int

The block timestamp

0

Returns:

Type Description
FixtureHeader

FixtureHeader instance with default values applied based on fork

FixtureHeader

requirements.

Raises:

Type Description
TypeError

If the overrides don't have the correct type.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
@classmethod
def build_default_block_header(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> FixtureHeader:
    """
    Build a default block header for this fork with the given attributes.

    This method automatically detects which header fields are required by
    the fork and assigns appropriate default values. It introspects the
    FixtureHeader model to find fields with HeaderForkRequirement
    annotations and automatically includes them if the fork requires them.

    Args:
        block_number: The block number
        timestamp: The block timestamp

    Returns:
        FixtureHeader instance with default values applied based on fork
        requirements.

    Raises:
        TypeError: If the overrides don't have the correct type.

    """
    from execution_testing.fixtures.blockchain import FixtureHeader

    defaults = {
        "number": ZeroPaddedHexNumber(block_number),
        "timestamp": ZeroPaddedHexNumber(timestamp),
        "fork": cls,
    }

    # Iterate through FixtureHeader fields to populate defaults
    for field_name, field_info in FixtureHeader.model_fields.items():
        if field_name in defaults:
            continue

        # Get default value, checking fork requirements and model defaults
        default_value = FixtureHeader.get_default_from_annotation(
            fork=cls,
            field_name=field_name,
            field_hint=field_info.annotation,
            block_number=int(block_number),
            timestamp=int(timestamp),
        )
        if default_value is not None:
            defaults[field_name] = default_value

    return FixtureHeader(**defaults)

GrayGlacier

Bases: ArrowGlacier

Gray Glacier fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2156
2157
2158
2159
class GrayGlacier(ArrowGlacier, solc_name="london", ignore=True):
    """Gray Glacier fork."""

    pass

Homestead

Bases: Frontier

Homestead fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
class Homestead(Frontier):
    """Homestead fork."""

    @classmethod
    def precompiles(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """
        At Homestead, EC-recover, SHA256, RIPEMD160, and Identity precompiles
        are introduced.
        """
        return [
            Address(1, label="ECREC"),
            Address(2, label="SHA256"),
            Address(3, label="RIPEMD160"),
            Address(4, label="ID"),
        ] + super(Homestead, cls).precompiles(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def call_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """At Homestead, DELEGATECALL opcode was introduced."""
        return [Opcodes.DELEGATECALL] + super(Homestead, cls).call_opcodes(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """Add DELEGATECALL opcode gas cost for Homestead."""
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        memory_expansion_calculator = cls.memory_expansion_gas_calculator(
            block_number=block_number, timestamp=timestamp
        )
        base_map = super(Homestead, cls).opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )
        return {
            **base_map,
            Opcodes.DELEGATECALL: cls._with_memory_expansion(
                lambda op: cls._calculate_call_gas(op, gas_costs),
                memory_expansion_calculator,
            ),
        }

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return the list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [Opcodes.DELEGATECALL] + super(Homestead, cls).valid_opcodes()

    @classmethod
    def transaction_intrinsic_cost_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> TransactionIntrinsicCostCalculator:
        """
        At Homestead, the transaction intrinsic cost needs to take contract
        creation into account.
        """
        super_fn = super(Homestead, cls).transaction_intrinsic_cost_calculator(
            block_number=block_number, timestamp=timestamp
        )
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )

        def fn(
            *,
            calldata: BytesConvertible = b"",
            contract_creation: bool = False,
            access_list: List[AccessList] | None = None,
            authorization_list_or_count: Sized | int | None = None,
            return_cost_deducted_prior_execution: bool = False,
        ) -> int:
            del return_cost_deducted_prior_execution

            intrinsic_cost: int = super_fn(
                calldata=calldata,
                contract_creation=contract_creation,
                access_list=access_list,
                authorization_list_or_count=authorization_list_or_count,
            )
            if contract_creation:
                intrinsic_cost += gas_costs.G_TRANSACTION_CREATE
            return intrinsic_cost

        return fn

precompiles(*, block_number=0, timestamp=0) classmethod

At Homestead, EC-recover, SHA256, RIPEMD160, and Identity precompiles are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
@classmethod
def precompiles(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """
    At Homestead, EC-recover, SHA256, RIPEMD160, and Identity precompiles
    are introduced.
    """
    return [
        Address(1, label="ECREC"),
        Address(2, label="SHA256"),
        Address(3, label="RIPEMD160"),
        Address(4, label="ID"),
    ] + super(Homestead, cls).precompiles(
        block_number=block_number, timestamp=timestamp
    )

call_opcodes(*, block_number=0, timestamp=0) classmethod

At Homestead, DELEGATECALL opcode was introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1480
1481
1482
1483
1484
1485
1486
1487
@classmethod
def call_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """At Homestead, DELEGATECALL opcode was introduced."""
    return [Opcodes.DELEGATECALL] + super(Homestead, cls).call_opcodes(
        block_number=block_number, timestamp=timestamp
    )

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Add DELEGATECALL opcode gas cost for Homestead.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """Add DELEGATECALL opcode gas cost for Homestead."""
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    memory_expansion_calculator = cls.memory_expansion_gas_calculator(
        block_number=block_number, timestamp=timestamp
    )
    base_map = super(Homestead, cls).opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )
    return {
        **base_map,
        Opcodes.DELEGATECALL: cls._with_memory_expansion(
            lambda op: cls._calculate_call_gas(op, gas_costs),
            memory_expansion_calculator,
        ),
    }

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return the list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1511
1512
1513
1514
1515
1516
1517
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return the list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [Opcodes.DELEGATECALL] + super(Homestead, cls).valid_opcodes()

transaction_intrinsic_cost_calculator(*, block_number=0, timestamp=0) classmethod

At Homestead, the transaction intrinsic cost needs to take contract creation into account.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
@classmethod
def transaction_intrinsic_cost_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> TransactionIntrinsicCostCalculator:
    """
    At Homestead, the transaction intrinsic cost needs to take contract
    creation into account.
    """
    super_fn = super(Homestead, cls).transaction_intrinsic_cost_calculator(
        block_number=block_number, timestamp=timestamp
    )
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )

    def fn(
        *,
        calldata: BytesConvertible = b"",
        contract_creation: bool = False,
        access_list: List[AccessList] | None = None,
        authorization_list_or_count: Sized | int | None = None,
        return_cost_deducted_prior_execution: bool = False,
    ) -> int:
        del return_cost_deducted_prior_execution

        intrinsic_cost: int = super_fn(
            calldata=calldata,
            contract_creation=contract_creation,
            access_list=access_list,
            authorization_list_or_count=authorization_list_or_count,
        )
        if contract_creation:
            intrinsic_cost += gas_costs.G_TRANSACTION_CREATE
        return intrinsic_cost

    return fn

Istanbul

Bases: ConstantinopleFix

Istanbul fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
class Istanbul(ConstantinopleFix):
    """Istanbul fork."""

    @classmethod
    def precompiles(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """At Istanbul, a precompile for blake2 compression is introduced."""
        return [
            Address(9, label="BLAKE2F"),
        ] + super(Istanbul, cls).precompiles(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """Add Istanbul opcodes gas costs."""
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        base_map = super(Istanbul, cls).opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )
        return {
            **base_map,
            Opcodes.CHAINID: gas_costs.G_BASE,
            Opcodes.SELFBALANCE: gas_costs.G_LOW,
        }

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [Opcodes.CHAINID, Opcodes.SELFBALANCE] + super(
            Istanbul, cls
        ).valid_opcodes()

    @classmethod
    def gas_costs(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> GasCosts:
        """
        On Istanbul, the non-zero transaction data byte cost is reduced to 16
        due to EIP-2028.
        """
        return replace(
            super(Istanbul, cls).gas_costs(
                block_number=block_number, timestamp=timestamp
            ),
            G_TX_DATA_NON_ZERO=16,  # https://eips.ethereum.org/EIPS/eip-2028
            # https://eips.ethereum.org/EIPS/eip-1108
            G_PRECOMPILE_ECADD=150,
            G_PRECOMPILE_ECMUL=6000,
            G_PRECOMPILE_ECPAIRING_BASE=45_000,
            G_PRECOMPILE_ECPAIRING_PER_POINT=34_000,
            G_PRECOMPILE_BLAKE2F_PER_ROUND=1,
        )

precompiles(*, block_number=0, timestamp=0) classmethod

At Istanbul, a precompile for blake2 compression is introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
@classmethod
def precompiles(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """At Istanbul, a precompile for blake2 compression is introduced."""
    return [
        Address(9, label="BLAKE2F"),
    ] + super(Istanbul, cls).precompiles(
        block_number=block_number, timestamp=timestamp
    )

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Add Istanbul opcodes gas costs.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """Add Istanbul opcodes gas costs."""
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    base_map = super(Istanbul, cls).opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )
    return {
        **base_map,
        Opcodes.CHAINID: gas_costs.G_BASE,
        Opcodes.SELFBALANCE: gas_costs.G_LOW,
    }

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1830
1831
1832
1833
1834
1835
1836
1837
1838
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [Opcodes.CHAINID, Opcodes.SELFBALANCE] + super(
        Istanbul, cls
    ).valid_opcodes()

gas_costs(*, block_number=0, timestamp=0) classmethod

On Istanbul, the non-zero transaction data byte cost is reduced to 16 due to EIP-2028.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
@classmethod
def gas_costs(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> GasCosts:
    """
    On Istanbul, the non-zero transaction data byte cost is reduced to 16
    due to EIP-2028.
    """
    return replace(
        super(Istanbul, cls).gas_costs(
            block_number=block_number, timestamp=timestamp
        ),
        G_TX_DATA_NON_ZERO=16,  # https://eips.ethereum.org/EIPS/eip-2028
        # https://eips.ethereum.org/EIPS/eip-1108
        G_PRECOMPILE_ECADD=150,
        G_PRECOMPILE_ECMUL=6000,
        G_PRECOMPILE_ECPAIRING_BASE=45_000,
        G_PRECOMPILE_ECPAIRING_PER_POINT=34_000,
        G_PRECOMPILE_BLAKE2F_PER_ROUND=1,
    )

London

Bases: Berlin

London fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
class London(Berlin):
    """London fork."""

    @classmethod
    def header_base_fee_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Header must contain the Base Fee starting from London."""
        del block_number, timestamp
        return True

    @classmethod
    def tx_types(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[int]:
        """At London, dynamic fee transactions are introduced."""
        return [2] + super(London, cls).tx_types(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def contract_creating_tx_types(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[int]:
        """At London, dynamic fee transactions are introduced."""
        return [2] + super(London, cls).contract_creating_tx_types(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """Add London opcodes gas costs."""
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        base_map = super(London, cls).opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )
        return {
            **base_map,
            Opcodes.BASEFEE: gas_costs.G_BASE,
        }

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [Opcodes.BASEFEE] + super(London, cls).valid_opcodes()

    @classmethod
    def max_refund_quotient(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the max refund quotient at London."""
        del block_number, timestamp
        return 5

    @classmethod
    def base_fee_max_change_denominator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the base fee max change denominator at London."""
        del block_number, timestamp
        return 8

    @classmethod
    def base_fee_elasticity_multiplier(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the base fee elasticity multiplier at London."""
        del block_number, timestamp
        return 2

    @classmethod
    def base_fee_per_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> BaseFeePerGasCalculator:
        """
        Return a callable that calculates the base fee per gas at London.

        EIP-1559 block validation pseudo code:

        if INITIAL_FORK_BLOCK_NUMBER == block.number:
            expected_base_fee_per_gas = INITIAL_BASE_FEE
        elif parent_gas_used == parent_gas_target:
            expected_base_fee_per_gas = parent_base_fee_per_gas
        elif parent_gas_used > parent_gas_target:
            gas_used_delta = parent_gas_used - parent_gas_target
            base_fee_per_gas_delta = max( parent_base_fee_per_gas
                                  * gas_used_delta // parent_gas_target //
                                  BASE_FEE_MAX_CHANGE_DENOMINATOR, 1, )
            expected_base_fee_per_gas = parent_base_fee_per_gas +
                                       base_fee_per_gas_delta
        else:
            gas_used_delta = parent_gas_target - parent_gas_used
            base_fee_per_gas_delta = (
                              parent_base_fee_per_gas * gas_used_delta //
                              parent_gas_target //
                              BASE_FEE_MAX_CHANGE_DENOMINATOR
                              )
            expected_base_fee_per_gas = parent_base_fee_per_gas -
                                        base_fee_per_gas_delta
        """
        base_fee_max_change_denominator = cls.base_fee_max_change_denominator(
            block_number=block_number, timestamp=timestamp
        )
        elasticity_multiplier = cls.base_fee_elasticity_multiplier(
            block_number=block_number, timestamp=timestamp
        )

        def fn(
            *,
            parent_base_fee_per_gas: int,
            parent_gas_used: int,
            parent_gas_limit: int,
        ) -> int:
            parent_gas_target = parent_gas_limit // elasticity_multiplier
            if parent_gas_used == parent_gas_target:
                return parent_base_fee_per_gas
            elif parent_gas_used > parent_gas_target:
                gas_used_delta = parent_gas_used - parent_gas_target
                base_fee_per_gas_delta = max(
                    parent_base_fee_per_gas
                    * gas_used_delta
                    // parent_gas_target
                    // base_fee_max_change_denominator,
                    1,
                )
                return parent_base_fee_per_gas + base_fee_per_gas_delta
            else:
                gas_used_delta = parent_gas_target - parent_gas_used
                base_fee_per_gas_delta = (
                    parent_base_fee_per_gas
                    * gas_used_delta
                    // parent_gas_target
                    // base_fee_max_change_denominator
                )
                return parent_base_fee_per_gas - base_fee_per_gas_delta

        return fn

    @classmethod
    def base_fee_change_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> BaseFeeChangeCalculator:
        """
        Return a callable that calculates the gas that needs to be used to
        change the base fee.
        """
        base_fee_max_change_denominator = cls.base_fee_max_change_denominator(
            block_number=block_number, timestamp=timestamp
        )
        elasticity_multiplier = cls.base_fee_elasticity_multiplier(
            block_number=block_number, timestamp=timestamp
        )
        base_fee_per_gas_calculator = cls.base_fee_per_gas_calculator(
            block_number=block_number, timestamp=timestamp
        )

        def fn(
            *,
            parent_base_fee_per_gas: int,
            parent_gas_limit: int,
            required_base_fee_per_gas: int,
        ) -> int:
            parent_gas_target = parent_gas_limit // elasticity_multiplier

            if parent_base_fee_per_gas == required_base_fee_per_gas:
                return parent_gas_target
            elif required_base_fee_per_gas > parent_base_fee_per_gas:
                # Base fee needs to go up, so we need to use more than target
                base_fee_per_gas_delta = (
                    required_base_fee_per_gas - parent_base_fee_per_gas
                )
                parent_gas_used = (
                    (
                        base_fee_per_gas_delta
                        * base_fee_max_change_denominator
                        * parent_gas_target
                    )
                    // parent_base_fee_per_gas
                ) + parent_gas_target
            elif required_base_fee_per_gas < parent_base_fee_per_gas:
                # Base fee needs to go down, so we need to use less than target
                base_fee_per_gas_delta = (
                    parent_base_fee_per_gas - required_base_fee_per_gas
                )

                parent_gas_used = (
                    parent_gas_target
                    - (
                        (
                            base_fee_per_gas_delta
                            * base_fee_max_change_denominator
                            * parent_gas_target
                        )
                        // parent_base_fee_per_gas
                    )
                    - 1
                )

            assert (
                base_fee_per_gas_calculator(
                    parent_base_fee_per_gas=parent_base_fee_per_gas,
                    parent_gas_used=parent_gas_used,
                    parent_gas_limit=parent_gas_limit,
                )
                == required_base_fee_per_gas
            )

            return parent_gas_used

        return fn

header_base_fee_required(*, block_number=0, timestamp=0) classmethod

Header must contain the Base Fee starting from London.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1933
1934
1935
1936
1937
1938
1939
@classmethod
def header_base_fee_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Header must contain the Base Fee starting from London."""
    del block_number, timestamp
    return True

tx_types(*, block_number=0, timestamp=0) classmethod

At London, dynamic fee transactions are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1941
1942
1943
1944
1945
1946
1947
1948
@classmethod
def tx_types(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[int]:
    """At London, dynamic fee transactions are introduced."""
    return [2] + super(London, cls).tx_types(
        block_number=block_number, timestamp=timestamp
    )

contract_creating_tx_types(*, block_number=0, timestamp=0) classmethod

At London, dynamic fee transactions are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1950
1951
1952
1953
1954
1955
1956
1957
@classmethod
def contract_creating_tx_types(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[int]:
    """At London, dynamic fee transactions are introduced."""
    return [2] + super(London, cls).contract_creating_tx_types(
        block_number=block_number, timestamp=timestamp
    )

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Add London opcodes gas costs.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """Add London opcodes gas costs."""
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    base_map = super(London, cls).opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )
    return {
        **base_map,
        Opcodes.BASEFEE: gas_costs.G_BASE,
    }

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1975
1976
1977
1978
1979
1980
1981
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [Opcodes.BASEFEE] + super(London, cls).valid_opcodes()

max_refund_quotient(*, block_number=0, timestamp=0) classmethod

Return the max refund quotient at London.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1983
1984
1985
1986
1987
1988
1989
@classmethod
def max_refund_quotient(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the max refund quotient at London."""
    del block_number, timestamp
    return 5

base_fee_max_change_denominator(*, block_number=0, timestamp=0) classmethod

Return the base fee max change denominator at London.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1991
1992
1993
1994
1995
1996
1997
@classmethod
def base_fee_max_change_denominator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the base fee max change denominator at London."""
    del block_number, timestamp
    return 8

base_fee_elasticity_multiplier(*, block_number=0, timestamp=0) classmethod

Return the base fee elasticity multiplier at London.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1999
2000
2001
2002
2003
2004
2005
@classmethod
def base_fee_elasticity_multiplier(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the base fee elasticity multiplier at London."""
    del block_number, timestamp
    return 2

base_fee_per_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the base fee per gas at London.

EIP-1559 block validation pseudo code:

if INITIAL_FORK_BLOCK_NUMBER == block.number: expected_base_fee_per_gas = INITIAL_BASE_FEE elif parent_gas_used == parent_gas_target: expected_base_fee_per_gas = parent_base_fee_per_gas elif parent_gas_used > parent_gas_target: gas_used_delta = parent_gas_used - parent_gas_target base_fee_per_gas_delta = max( parent_base_fee_per_gas * gas_used_delta // parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR, 1, ) expected_base_fee_per_gas = parent_base_fee_per_gas + base_fee_per_gas_delta else: gas_used_delta = parent_gas_target - parent_gas_used base_fee_per_gas_delta = ( parent_base_fee_per_gas * gas_used_delta // parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR ) expected_base_fee_per_gas = parent_base_fee_per_gas - base_fee_per_gas_delta

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
@classmethod
def base_fee_per_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> BaseFeePerGasCalculator:
    """
    Return a callable that calculates the base fee per gas at London.

    EIP-1559 block validation pseudo code:

    if INITIAL_FORK_BLOCK_NUMBER == block.number:
        expected_base_fee_per_gas = INITIAL_BASE_FEE
    elif parent_gas_used == parent_gas_target:
        expected_base_fee_per_gas = parent_base_fee_per_gas
    elif parent_gas_used > parent_gas_target:
        gas_used_delta = parent_gas_used - parent_gas_target
        base_fee_per_gas_delta = max( parent_base_fee_per_gas
                              * gas_used_delta // parent_gas_target //
                              BASE_FEE_MAX_CHANGE_DENOMINATOR, 1, )
        expected_base_fee_per_gas = parent_base_fee_per_gas +
                                   base_fee_per_gas_delta
    else:
        gas_used_delta = parent_gas_target - parent_gas_used
        base_fee_per_gas_delta = (
                          parent_base_fee_per_gas * gas_used_delta //
                          parent_gas_target //
                          BASE_FEE_MAX_CHANGE_DENOMINATOR
                          )
        expected_base_fee_per_gas = parent_base_fee_per_gas -
                                    base_fee_per_gas_delta
    """
    base_fee_max_change_denominator = cls.base_fee_max_change_denominator(
        block_number=block_number, timestamp=timestamp
    )
    elasticity_multiplier = cls.base_fee_elasticity_multiplier(
        block_number=block_number, timestamp=timestamp
    )

    def fn(
        *,
        parent_base_fee_per_gas: int,
        parent_gas_used: int,
        parent_gas_limit: int,
    ) -> int:
        parent_gas_target = parent_gas_limit // elasticity_multiplier
        if parent_gas_used == parent_gas_target:
            return parent_base_fee_per_gas
        elif parent_gas_used > parent_gas_target:
            gas_used_delta = parent_gas_used - parent_gas_target
            base_fee_per_gas_delta = max(
                parent_base_fee_per_gas
                * gas_used_delta
                // parent_gas_target
                // base_fee_max_change_denominator,
                1,
            )
            return parent_base_fee_per_gas + base_fee_per_gas_delta
        else:
            gas_used_delta = parent_gas_target - parent_gas_used
            base_fee_per_gas_delta = (
                parent_base_fee_per_gas
                * gas_used_delta
                // parent_gas_target
                // base_fee_max_change_denominator
            )
            return parent_base_fee_per_gas - base_fee_per_gas_delta

    return fn

base_fee_change_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the gas that needs to be used to change the base fee.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
@classmethod
def base_fee_change_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> BaseFeeChangeCalculator:
    """
    Return a callable that calculates the gas that needs to be used to
    change the base fee.
    """
    base_fee_max_change_denominator = cls.base_fee_max_change_denominator(
        block_number=block_number, timestamp=timestamp
    )
    elasticity_multiplier = cls.base_fee_elasticity_multiplier(
        block_number=block_number, timestamp=timestamp
    )
    base_fee_per_gas_calculator = cls.base_fee_per_gas_calculator(
        block_number=block_number, timestamp=timestamp
    )

    def fn(
        *,
        parent_base_fee_per_gas: int,
        parent_gas_limit: int,
        required_base_fee_per_gas: int,
    ) -> int:
        parent_gas_target = parent_gas_limit // elasticity_multiplier

        if parent_base_fee_per_gas == required_base_fee_per_gas:
            return parent_gas_target
        elif required_base_fee_per_gas > parent_base_fee_per_gas:
            # Base fee needs to go up, so we need to use more than target
            base_fee_per_gas_delta = (
                required_base_fee_per_gas - parent_base_fee_per_gas
            )
            parent_gas_used = (
                (
                    base_fee_per_gas_delta
                    * base_fee_max_change_denominator
                    * parent_gas_target
                )
                // parent_base_fee_per_gas
            ) + parent_gas_target
        elif required_base_fee_per_gas < parent_base_fee_per_gas:
            # Base fee needs to go down, so we need to use less than target
            base_fee_per_gas_delta = (
                parent_base_fee_per_gas - required_base_fee_per_gas
            )

            parent_gas_used = (
                parent_gas_target
                - (
                    (
                        base_fee_per_gas_delta
                        * base_fee_max_change_denominator
                        * parent_gas_target
                    )
                    // parent_base_fee_per_gas
                )
                - 1
            )

        assert (
            base_fee_per_gas_calculator(
                parent_base_fee_per_gas=parent_base_fee_per_gas,
                parent_gas_used=parent_gas_used,
                parent_gas_limit=parent_gas_limit,
            )
            == required_base_fee_per_gas
        )

        return parent_gas_used

    return fn

MuirGlacier

Bases: Istanbul

Muir Glacier fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1863
1864
1865
1866
class MuirGlacier(Istanbul, solc_name="istanbul", ignore=True):
    """Muir Glacier fork."""

    pass

Osaka

Bases: Prague

Osaka fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
class Osaka(Prague, solc_name="cancun"):
    """Osaka fork."""

    # update some blob constants
    BLOB_CONSTANTS = {
        **Prague.BLOB_CONSTANTS,  # same base constants as prague
        "AMOUNT_CELL_PROOFS": 128,
    }

    @classmethod
    def engine_get_payload_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """From Osaka, get payload calls must use version 5."""
        del block_number, timestamp
        return 5

    @classmethod
    def engine_get_blobs_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """At Osaka, the engine get blobs version is 2."""
        del block_number, timestamp
        return 2

    @classmethod
    def full_blob_tx_wrapper_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int | None:
        """At Osaka, the full blob transaction wrapper version is defined."""
        del block_number, timestamp
        return 1

    @classmethod
    def transaction_gas_limit_cap(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int | None:
        """At Osaka, transaction gas limit is capped at 16 million (2**24)."""
        del block_number, timestamp
        return 16_777_216

    @classmethod
    def block_rlp_size_limit(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int | None:
        """From Osaka, block RLP size is limited as specified in EIP-7934."""
        del block_number, timestamp

        max_block_size = 10_485_760
        safety_margin = 2_097_152
        return max_block_size - safety_margin

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """Add Osaka opcodes gas costs."""
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        base_map = super(Osaka, cls).opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )
        return {
            **base_map,
            Opcodes.CLZ: gas_costs.G_LOW,
        }

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [
            Opcodes.CLZ,
        ] + super(Prague, cls).valid_opcodes()

    @classmethod
    def precompiles(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """
        At Osaka, a precompile for p256verify operation is added.

        P256VERIFY = 0x100
        """
        return [
            Address(0x100, label="P256VERIFY"),
        ] + super(Osaka, cls).precompiles(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def gas_costs(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> GasCosts:
        """On Osaka, the P256VERIFY precompile gas cost is set."""
        return replace(
            super(Osaka, cls).gas_costs(
                block_number=block_number, timestamp=timestamp
            ),
            G_PRECOMPILE_P256VERIFY=6_900,
        )

    @classmethod
    def excess_blob_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> ExcessBlobGasCalculator:
        """
        Return a callable that calculates the excess blob gas for a block.
        """
        target_blobs_per_block = cls.target_blobs_per_block(
            block_number=block_number, timestamp=timestamp
        )
        blob_gas_per_blob = cls.blob_gas_per_blob(
            block_number=block_number, timestamp=timestamp
        )
        target_blob_gas_per_block = target_blobs_per_block * blob_gas_per_blob
        max_blobs_per_block = cls.max_blobs_per_block(
            block_number=block_number, timestamp=timestamp
        )
        blob_base_cost = 2**13  # EIP-7918 new parameter

        def fn(
            *,
            parent_excess_blob_gas: int | None = None,
            parent_excess_blobs: int | None = None,
            parent_blob_gas_used: int | None = None,
            parent_blob_count: int | None = None,
            parent_base_fee_per_gas: int,  # EIP-7918 additional parameter
        ) -> int:
            if parent_excess_blob_gas is None:
                assert parent_excess_blobs is not None, (
                    "Parent excess blobs are required"
                )
                parent_excess_blob_gas = (
                    parent_excess_blobs * blob_gas_per_blob
                )
            if parent_blob_gas_used is None:
                assert parent_blob_count is not None, (
                    "Parent blob count is required"
                )
                parent_blob_gas_used = parent_blob_count * blob_gas_per_blob
            if (
                parent_excess_blob_gas + parent_blob_gas_used
                < target_blob_gas_per_block
            ):
                return 0

            # EIP-7918: Apply reserve price when execution costs dominate blob
            # costs
            current_blob_base_fee = cls.blob_gas_price_calculator()(
                excess_blob_gas=parent_excess_blob_gas
            )
            reserve_price_active = (
                blob_base_cost * parent_base_fee_per_gas
                > blob_gas_per_blob * current_blob_base_fee
            )
            if reserve_price_active:
                blob_excess_adjustment = (
                    parent_blob_gas_used
                    * (max_blobs_per_block - target_blobs_per_block)
                    // max_blobs_per_block
                )
                return parent_excess_blob_gas + blob_excess_adjustment

            # Original EIP-4844 calculation
            return (
                parent_excess_blob_gas
                + parent_blob_gas_used
                - target_blob_gas_per_block
            )

        return fn

    @classmethod
    def max_blobs_per_tx(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """
        Blobs in Osaka, have a static max of 6 blobs per tx. Differs from the
        max per block.
        """
        del block_number, timestamp
        return 6

    @classmethod
    def blob_reserve_price_active(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Blob reserve price is supported in Osaka."""
        del block_number, timestamp
        return True

    @classmethod
    def blob_base_cost(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the base cost of a blob at a given fork."""
        del block_number, timestamp
        return 2**13  # EIP-7918 new parameter

engine_get_payload_version(*, block_number=0, timestamp=0) classmethod

From Osaka, get payload calls must use version 5.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3077
3078
3079
3080
3081
3082
3083
@classmethod
def engine_get_payload_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """From Osaka, get payload calls must use version 5."""
    del block_number, timestamp
    return 5

engine_get_blobs_version(*, block_number=0, timestamp=0) classmethod

At Osaka, the engine get blobs version is 2.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3085
3086
3087
3088
3089
3090
3091
@classmethod
def engine_get_blobs_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """At Osaka, the engine get blobs version is 2."""
    del block_number, timestamp
    return 2

full_blob_tx_wrapper_version(*, block_number=0, timestamp=0) classmethod

At Osaka, the full blob transaction wrapper version is defined.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3093
3094
3095
3096
3097
3098
3099
@classmethod
def full_blob_tx_wrapper_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int | None:
    """At Osaka, the full blob transaction wrapper version is defined."""
    del block_number, timestamp
    return 1

transaction_gas_limit_cap(*, block_number=0, timestamp=0) classmethod

At Osaka, transaction gas limit is capped at 16 million (2**24).

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3101
3102
3103
3104
3105
3106
3107
@classmethod
def transaction_gas_limit_cap(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int | None:
    """At Osaka, transaction gas limit is capped at 16 million (2**24)."""
    del block_number, timestamp
    return 16_777_216

block_rlp_size_limit(*, block_number=0, timestamp=0) classmethod

From Osaka, block RLP size is limited as specified in EIP-7934.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
@classmethod
def block_rlp_size_limit(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int | None:
    """From Osaka, block RLP size is limited as specified in EIP-7934."""
    del block_number, timestamp

    max_block_size = 10_485_760
    safety_margin = 2_097_152
    return max_block_size - safety_margin

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Add Osaka opcodes gas costs.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """Add Osaka opcodes gas costs."""
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    base_map = super(Osaka, cls).opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )
    return {
        **base_map,
        Opcodes.CLZ: gas_costs.G_LOW,
    }

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3136
3137
3138
3139
3140
3141
3142
3143
3144
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [
        Opcodes.CLZ,
    ] + super(Prague, cls).valid_opcodes()

precompiles(*, block_number=0, timestamp=0) classmethod

At Osaka, a precompile for p256verify operation is added.

P256VERIFY = 0x100

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
@classmethod
def precompiles(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """
    At Osaka, a precompile for p256verify operation is added.

    P256VERIFY = 0x100
    """
    return [
        Address(0x100, label="P256VERIFY"),
    ] + super(Osaka, cls).precompiles(
        block_number=block_number, timestamp=timestamp
    )

gas_costs(*, block_number=0, timestamp=0) classmethod

On Osaka, the P256VERIFY precompile gas cost is set.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
@classmethod
def gas_costs(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> GasCosts:
    """On Osaka, the P256VERIFY precompile gas cost is set."""
    return replace(
        super(Osaka, cls).gas_costs(
            block_number=block_number, timestamp=timestamp
        ),
        G_PRECOMPILE_P256VERIFY=6_900,
    )

excess_blob_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the excess blob gas for a block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
@classmethod
def excess_blob_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> ExcessBlobGasCalculator:
    """
    Return a callable that calculates the excess blob gas for a block.
    """
    target_blobs_per_block = cls.target_blobs_per_block(
        block_number=block_number, timestamp=timestamp
    )
    blob_gas_per_blob = cls.blob_gas_per_blob(
        block_number=block_number, timestamp=timestamp
    )
    target_blob_gas_per_block = target_blobs_per_block * blob_gas_per_blob
    max_blobs_per_block = cls.max_blobs_per_block(
        block_number=block_number, timestamp=timestamp
    )
    blob_base_cost = 2**13  # EIP-7918 new parameter

    def fn(
        *,
        parent_excess_blob_gas: int | None = None,
        parent_excess_blobs: int | None = None,
        parent_blob_gas_used: int | None = None,
        parent_blob_count: int | None = None,
        parent_base_fee_per_gas: int,  # EIP-7918 additional parameter
    ) -> int:
        if parent_excess_blob_gas is None:
            assert parent_excess_blobs is not None, (
                "Parent excess blobs are required"
            )
            parent_excess_blob_gas = (
                parent_excess_blobs * blob_gas_per_blob
            )
        if parent_blob_gas_used is None:
            assert parent_blob_count is not None, (
                "Parent blob count is required"
            )
            parent_blob_gas_used = parent_blob_count * blob_gas_per_blob
        if (
            parent_excess_blob_gas + parent_blob_gas_used
            < target_blob_gas_per_block
        ):
            return 0

        # EIP-7918: Apply reserve price when execution costs dominate blob
        # costs
        current_blob_base_fee = cls.blob_gas_price_calculator()(
            excess_blob_gas=parent_excess_blob_gas
        )
        reserve_price_active = (
            blob_base_cost * parent_base_fee_per_gas
            > blob_gas_per_blob * current_blob_base_fee
        )
        if reserve_price_active:
            blob_excess_adjustment = (
                parent_blob_gas_used
                * (max_blobs_per_block - target_blobs_per_block)
                // max_blobs_per_block
            )
            return parent_excess_blob_gas + blob_excess_adjustment

        # Original EIP-4844 calculation
        return (
            parent_excess_blob_gas
            + parent_blob_gas_used
            - target_blob_gas_per_block
        )

    return fn

max_blobs_per_tx(*, block_number=0, timestamp=0) classmethod

Blobs in Osaka, have a static max of 6 blobs per tx. Differs from the max per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
@classmethod
def max_blobs_per_tx(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """
    Blobs in Osaka, have a static max of 6 blobs per tx. Differs from the
    max per block.
    """
    del block_number, timestamp
    return 6

blob_reserve_price_active(*, block_number=0, timestamp=0) classmethod

Blob reserve price is supported in Osaka.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3255
3256
3257
3258
3259
3260
3261
@classmethod
def blob_reserve_price_active(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Blob reserve price is supported in Osaka."""
    del block_number, timestamp
    return True

blob_base_cost(*, block_number=0, timestamp=0) classmethod

Return the base cost of a blob at a given fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3263
3264
3265
3266
3267
3268
3269
@classmethod
def blob_base_cost(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the base cost of a blob at a given fork."""
    del block_number, timestamp
    return 2**13  # EIP-7918 new parameter

Paris

Bases: London

Paris (Merge) fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
class Paris(
    London,
    transition_tool_name="Merge",
):
    """Paris (Merge) fork."""

    @classmethod
    def header_prev_randao_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Prev Randao is required starting from Paris."""
        del block_number, timestamp
        return True

    @classmethod
    def header_zero_difficulty_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Zero difficulty is required starting from Paris."""
        del block_number, timestamp
        return True

    @classmethod
    def get_reward(cls, *, block_number: int = 0, timestamp: int = 0) -> int:
        """Paris updates the reward to 0."""
        del block_number, timestamp
        return 0

    @classmethod
    def engine_new_payload_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """From Paris, payloads can be sent through the engine API."""
        del block_number, timestamp
        return 1

header_prev_randao_required(*, block_number=0, timestamp=0) classmethod

Prev Randao is required starting from Paris.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2168
2169
2170
2171
2172
2173
2174
@classmethod
def header_prev_randao_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Prev Randao is required starting from Paris."""
    del block_number, timestamp
    return True

header_zero_difficulty_required(*, block_number=0, timestamp=0) classmethod

Zero difficulty is required starting from Paris.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2176
2177
2178
2179
2180
2181
2182
@classmethod
def header_zero_difficulty_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Zero difficulty is required starting from Paris."""
    del block_number, timestamp
    return True

get_reward(*, block_number=0, timestamp=0) classmethod

Paris updates the reward to 0.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2184
2185
2186
2187
2188
@classmethod
def get_reward(cls, *, block_number: int = 0, timestamp: int = 0) -> int:
    """Paris updates the reward to 0."""
    del block_number, timestamp
    return 0

engine_new_payload_version(*, block_number=0, timestamp=0) classmethod

From Paris, payloads can be sent through the engine API.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2190
2191
2192
2193
2194
2195
2196
@classmethod
def engine_new_payload_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """From Paris, payloads can be sent through the engine API."""
    del block_number, timestamp
    return 1

Prague

Bases: Cancun

Prague fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
class Prague(Cancun):
    """Prague fork."""

    # update some blob constants
    BLOB_CONSTANTS = {
        **Cancun.BLOB_CONSTANTS,  # same base constants as cancun
        "MAX_BLOBS_PER_BLOCK": 9,  # but overwrite or add these
        "TARGET_BLOBS_PER_BLOCK": 6,
        "MAX_BLOB_GAS_PER_BLOCK": 1179648,
        "TARGET_BLOB_GAS_PER_BLOCK": 786432,
        "BLOB_BASE_FEE_UPDATE_FRACTION": 5007716,
    }

    @classmethod
    def precompiles(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """
        At Prague, precompiles for BLS operations are added.

        BLS12_G1ADD = 0x0B
        BLS12_G1MSM = 0x0C
        BLS12_G2ADD = 0x0D
        BLS12_G2MSM = 0x0E
        BLS12_PAIRING_CHECK = 0x0F
        BLS12_MAP_FP_TO_G1 = 0x10
        BLS12_MAP_FP2_TO_G2 = 0x11
        """
        return [
            Address(11, label="BLS12_G1ADD"),
            Address(12, label="BLS12_G1MSM"),
            Address(13, label="BLS12_G2ADD"),
            Address(14, label="BLS12_G2MSM"),
            Address(15, label="BLS12_PAIRING_CHECK"),
            Address(16, label="BLS12_MAP_FP_TO_G1"),
            Address(17, label="BLS12_MAP_FP2_TO_G2"),
        ] + super(Prague, cls).precompiles(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def tx_types(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[int]:
        """At Prague, set-code type transactions are introduced."""
        return [4] + super(Prague, cls).tx_types(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def gas_costs(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> GasCosts:
        """
        On Prague, the standard token cost and the floor token costs are
        introduced due to EIP-7623.
        """
        return replace(
            super(Prague, cls).gas_costs(
                block_number=block_number, timestamp=timestamp
            ),
            G_TX_DATA_STANDARD_TOKEN_COST=4,  # https://eips.ethereum.org/EIPS/eip-7623
            G_TX_DATA_FLOOR_TOKEN_COST=10,
            G_AUTHORIZATION=25_000,
            R_AUTHORIZATION_EXISTING_AUTHORITY=12_500,
            G_PRECOMPILE_BLS_G1ADD=375,
            G_PRECOMPILE_BLS_G1MUL=12_000,
            G_PRECOMPILE_BLS_G1MAP=5_500,
            G_PRECOMPILE_BLS_G2ADD=600,
            G_PRECOMPILE_BLS_G2MUL=22_500,
            G_PRECOMPILE_BLS_G2MAP=23_800,
            G_PRECOMPILE_BLS_PAIRING_BASE=37_700,
            G_PRECOMPILE_BLS_PAIRING_PER_PAIR=32_600,
        )

    @classmethod
    def system_contracts(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Address]:
        """
        Prague introduces the system contracts for EIP-6110, EIP-7002, EIP-7251
        and EIP-2935.
        """
        return [
            Address(
                0x00000000219AB540356CBB839CBE05303D7705FA,
                label="DEPOSIT_CONTRACT_ADDRESS",
            ),
            Address(
                0x00000961EF480EB55E80D19AD83579A64C007002,
                label="WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS",
            ),
            Address(
                0x0000BBDDC7CE488642FB579F8B00F3A590007251,
                label="CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS",
            ),
            Address(
                0x0000F90827F1C53A10CB7A02335B175320002935,
                label="HISTORY_STORAGE_ADDRESS",
            ),
        ] + super(Prague, cls).system_contracts(
            block_number=block_number, timestamp=timestamp
        )

    @classmethod
    def max_request_type(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """
        At Prague, three request types are introduced, hence the max request
        type is 2.
        """
        del block_number, timestamp
        return 2

    @classmethod
    def calldata_gas_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> CalldataGasCalculator:
        """
        Return a callable that calculates the transaction gas cost for its
        calldata depending on its contents.
        """
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )

        def fn(*, data: BytesConvertible, floor: bool = False) -> int:
            tokens = 0
            for b in Bytes(data):
                if b == 0:
                    tokens += 1
                else:
                    tokens += 4
            if floor:
                return tokens * gas_costs.G_TX_DATA_FLOOR_TOKEN_COST
            return tokens * gas_costs.G_TX_DATA_STANDARD_TOKEN_COST

        return fn

    @classmethod
    def _calculate_call_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """
        At Prague, the call gas cost needs to take the authorization into
        account.
        """
        metadata = opcode.metadata

        base_cost = super(Prague, cls)._calculate_call_gas(opcode, gas_costs)

        if metadata["delegated_address"] or metadata["delegated_address_warm"]:
            if metadata["delegated_address_warm"]:
                base_cost += gas_costs.G_WARM_ACCOUNT_ACCESS
            else:
                base_cost += gas_costs.G_COLD_ACCOUNT_ACCESS

        return base_cost

    @classmethod
    def transaction_data_floor_cost_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> TransactionDataFloorCostCalculator:
        """
        On Prague, due to EIP-7623, the transaction data floor cost is
        introduced.
        """
        calldata_gas_calculator = cls.calldata_gas_calculator(
            block_number=block_number, timestamp=timestamp
        )
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )

        def fn(*, data: BytesConvertible) -> int:
            return (
                calldata_gas_calculator(data=data, floor=True)
                + gas_costs.G_TRANSACTION
            )

        return fn

    @classmethod
    def transaction_intrinsic_cost_calculator(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> TransactionIntrinsicCostCalculator:
        """
        At Prague, the transaction intrinsic cost needs to take the
        authorizations into account.
        """
        super_fn = super(Prague, cls).transaction_intrinsic_cost_calculator(
            block_number=block_number, timestamp=timestamp
        )
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        transaction_data_floor_cost_calculator = (
            cls.transaction_data_floor_cost_calculator(
                block_number=block_number, timestamp=timestamp
            )
        )

        def fn(
            *,
            calldata: BytesConvertible = b"",
            contract_creation: bool = False,
            access_list: List[AccessList] | None = None,
            authorization_list_or_count: Sized | int | None = None,
            return_cost_deducted_prior_execution: bool = False,
        ) -> int:
            intrinsic_cost: int = super_fn(
                calldata=calldata,
                contract_creation=contract_creation,
                access_list=access_list,
                return_cost_deducted_prior_execution=False,
            )
            if authorization_list_or_count is not None:
                if isinstance(authorization_list_or_count, Sized):
                    authorization_list_or_count = len(
                        authorization_list_or_count
                    )
                intrinsic_cost += (
                    authorization_list_or_count * gas_costs.G_AUTHORIZATION
                )

            if return_cost_deducted_prior_execution:
                return intrinsic_cost

            transaction_floor_data_cost = (
                transaction_data_floor_cost_calculator(data=calldata)
            )
            return max(intrinsic_cost, transaction_floor_data_cost)

        return fn

    @classmethod
    def blob_base_fee_update_fraction(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Return the blob base fee update fraction for Prague."""
        del block_number, timestamp
        return 5007716

    @classmethod
    def target_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in Prague, have a static target of 6 blobs per block."""
        del block_number, timestamp
        return 6

    @classmethod
    def max_blobs_per_block(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """Blobs in Prague, have a static max of 9 blobs per block."""
        del block_number, timestamp
        return 9

    @classmethod
    def pre_allocation_blockchain(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Mapping:
        """
        Prague requires pre-allocation of the beacon chain deposit contract for
        EIP-6110, the exits contract for EIP-7002, and the history storage
        contract for EIP-2935.
        """
        del block_number, timestamp
        new_allocation = {}

        # Add the beacon chain deposit contract
        deposit_contract_tree_depth = 32
        storage = {}
        next_hash = sha256(b"\x00" * 64).digest()
        for i in range(
            deposit_contract_tree_depth + 2,
            deposit_contract_tree_depth * 2 + 1,
        ):
            storage[i] = next_hash
            next_hash = sha256(next_hash + next_hash).digest()

        with open(
            CURRENT_FOLDER / "contracts" / "deposit_contract.bin", mode="rb"
        ) as f:
            new_allocation.update(
                {
                    0x00000000219AB540356CBB839CBE05303D7705FA: {
                        "nonce": 1,
                        "code": f.read(),
                        "storage": storage,
                    }
                }
            )

        # EIP-7002: Add the withdrawal request contract
        with open(
            CURRENT_FOLDER / "contracts" / "withdrawal_request.bin", mode="rb"
        ) as f:
            new_allocation.update(
                {
                    0x00000961EF480EB55E80D19AD83579A64C007002: {
                        "nonce": 1,
                        "code": f.read(),
                    },
                }
            )

        # EIP-7251: Add the consolidation request contract
        with open(
            CURRENT_FOLDER / "contracts" / "consolidation_request.bin",
            mode="rb",
        ) as f:
            new_allocation.update(
                {
                    0x0000BBDDC7CE488642FB579F8B00F3A590007251: {
                        "nonce": 1,
                        "code": f.read(),
                    },
                }
            )

        # EIP-2935: Add the history storage contract
        with open(
            CURRENT_FOLDER / "contracts" / "history_contract.bin", mode="rb"
        ) as f:
            new_allocation.update(
                {
                    0x0000F90827F1C53A10CB7A02335B175320002935: {
                        "nonce": 1,
                        "code": f.read(),
                    }
                }
            )

        return new_allocation | super(Prague, cls).pre_allocation_blockchain()  # type: ignore

    @classmethod
    def header_requests_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """
        Prague requires that the execution layer header contains the beacon
        chain requests hash.
        """
        del block_number, timestamp
        return True

    @classmethod
    def engine_new_payload_requests(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """
        From Prague, new payloads include the requests hash as a parameter.
        """
        del block_number, timestamp
        return True

    @classmethod
    def engine_new_payload_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """From Prague, new payload calls must use version 4."""
        del block_number, timestamp
        return 4

    @classmethod
    def engine_forkchoice_updated_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """
        At Prague, version number of NewPayload and ForkchoiceUpdated diverge.
        """
        del block_number, timestamp
        return 3

precompiles(*, block_number=0, timestamp=0) classmethod

At Prague, precompiles for BLS operations are added.

BLS12_G1ADD = 0x0B BLS12_G1MSM = 0x0C BLS12_G2ADD = 0x0D BLS12_G2MSM = 0x0E BLS12_PAIRING_CHECK = 0x0F BLS12_MAP_FP_TO_G1 = 0x10 BLS12_MAP_FP2_TO_G2 = 0x11

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
@classmethod
def precompiles(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """
    At Prague, precompiles for BLS operations are added.

    BLS12_G1ADD = 0x0B
    BLS12_G1MSM = 0x0C
    BLS12_G2ADD = 0x0D
    BLS12_G2MSM = 0x0E
    BLS12_PAIRING_CHECK = 0x0F
    BLS12_MAP_FP_TO_G1 = 0x10
    BLS12_MAP_FP2_TO_G2 = 0x11
    """
    return [
        Address(11, label="BLS12_G1ADD"),
        Address(12, label="BLS12_G1MSM"),
        Address(13, label="BLS12_G2ADD"),
        Address(14, label="BLS12_G2MSM"),
        Address(15, label="BLS12_PAIRING_CHECK"),
        Address(16, label="BLS12_MAP_FP_TO_G1"),
        Address(17, label="BLS12_MAP_FP2_TO_G2"),
    ] + super(Prague, cls).precompiles(
        block_number=block_number, timestamp=timestamp
    )

tx_types(*, block_number=0, timestamp=0) classmethod

At Prague, set-code type transactions are introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2730
2731
2732
2733
2734
2735
2736
2737
@classmethod
def tx_types(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[int]:
    """At Prague, set-code type transactions are introduced."""
    return [4] + super(Prague, cls).tx_types(
        block_number=block_number, timestamp=timestamp
    )

gas_costs(*, block_number=0, timestamp=0) classmethod

On Prague, the standard token cost and the floor token costs are introduced due to EIP-7623.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
@classmethod
def gas_costs(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> GasCosts:
    """
    On Prague, the standard token cost and the floor token costs are
    introduced due to EIP-7623.
    """
    return replace(
        super(Prague, cls).gas_costs(
            block_number=block_number, timestamp=timestamp
        ),
        G_TX_DATA_STANDARD_TOKEN_COST=4,  # https://eips.ethereum.org/EIPS/eip-7623
        G_TX_DATA_FLOOR_TOKEN_COST=10,
        G_AUTHORIZATION=25_000,
        R_AUTHORIZATION_EXISTING_AUTHORITY=12_500,
        G_PRECOMPILE_BLS_G1ADD=375,
        G_PRECOMPILE_BLS_G1MUL=12_000,
        G_PRECOMPILE_BLS_G1MAP=5_500,
        G_PRECOMPILE_BLS_G2ADD=600,
        G_PRECOMPILE_BLS_G2MUL=22_500,
        G_PRECOMPILE_BLS_G2MAP=23_800,
        G_PRECOMPILE_BLS_PAIRING_BASE=37_700,
        G_PRECOMPILE_BLS_PAIRING_PER_PAIR=32_600,
    )

system_contracts(*, block_number=0, timestamp=0) classmethod

Prague introduces the system contracts for EIP-6110, EIP-7002, EIP-7251 and EIP-2935.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
@classmethod
def system_contracts(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Address]:
    """
    Prague introduces the system contracts for EIP-6110, EIP-7002, EIP-7251
    and EIP-2935.
    """
    return [
        Address(
            0x00000000219AB540356CBB839CBE05303D7705FA,
            label="DEPOSIT_CONTRACT_ADDRESS",
        ),
        Address(
            0x00000961EF480EB55E80D19AD83579A64C007002,
            label="WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS",
        ),
        Address(
            0x0000BBDDC7CE488642FB579F8B00F3A590007251,
            label="CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS",
        ),
        Address(
            0x0000F90827F1C53A10CB7A02335B175320002935,
            label="HISTORY_STORAGE_ADDRESS",
        ),
    ] + super(Prague, cls).system_contracts(
        block_number=block_number, timestamp=timestamp
    )

max_request_type(*, block_number=0, timestamp=0) classmethod

At Prague, three request types are introduced, hence the max request type is 2.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
@classmethod
def max_request_type(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """
    At Prague, three request types are introduced, hence the max request
    type is 2.
    """
    del block_number, timestamp
    return 2

calldata_gas_calculator(*, block_number=0, timestamp=0) classmethod

Return a callable that calculates the transaction gas cost for its calldata depending on its contents.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
@classmethod
def calldata_gas_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> CalldataGasCalculator:
    """
    Return a callable that calculates the transaction gas cost for its
    calldata depending on its contents.
    """
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )

    def fn(*, data: BytesConvertible, floor: bool = False) -> int:
        tokens = 0
        for b in Bytes(data):
            if b == 0:
                tokens += 1
            else:
                tokens += 4
        if floor:
            return tokens * gas_costs.G_TX_DATA_FLOOR_TOKEN_COST
        return tokens * gas_costs.G_TX_DATA_STANDARD_TOKEN_COST

    return fn

transaction_data_floor_cost_calculator(*, block_number=0, timestamp=0) classmethod

On Prague, due to EIP-7623, the transaction data floor cost is introduced.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
@classmethod
def transaction_data_floor_cost_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> TransactionDataFloorCostCalculator:
    """
    On Prague, due to EIP-7623, the transaction data floor cost is
    introduced.
    """
    calldata_gas_calculator = cls.calldata_gas_calculator(
        block_number=block_number, timestamp=timestamp
    )
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )

    def fn(*, data: BytesConvertible) -> int:
        return (
            calldata_gas_calculator(data=data, floor=True)
            + gas_costs.G_TRANSACTION
        )

    return fn

transaction_intrinsic_cost_calculator(*, block_number=0, timestamp=0) classmethod

At Prague, the transaction intrinsic cost needs to take the authorizations into account.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
@classmethod
def transaction_intrinsic_cost_calculator(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> TransactionIntrinsicCostCalculator:
    """
    At Prague, the transaction intrinsic cost needs to take the
    authorizations into account.
    """
    super_fn = super(Prague, cls).transaction_intrinsic_cost_calculator(
        block_number=block_number, timestamp=timestamp
    )
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    transaction_data_floor_cost_calculator = (
        cls.transaction_data_floor_cost_calculator(
            block_number=block_number, timestamp=timestamp
        )
    )

    def fn(
        *,
        calldata: BytesConvertible = b"",
        contract_creation: bool = False,
        access_list: List[AccessList] | None = None,
        authorization_list_or_count: Sized | int | None = None,
        return_cost_deducted_prior_execution: bool = False,
    ) -> int:
        intrinsic_cost: int = super_fn(
            calldata=calldata,
            contract_creation=contract_creation,
            access_list=access_list,
            return_cost_deducted_prior_execution=False,
        )
        if authorization_list_or_count is not None:
            if isinstance(authorization_list_or_count, Sized):
                authorization_list_or_count = len(
                    authorization_list_or_count
                )
            intrinsic_cost += (
                authorization_list_or_count * gas_costs.G_AUTHORIZATION
            )

        if return_cost_deducted_prior_execution:
            return intrinsic_cost

        transaction_floor_data_cost = (
            transaction_data_floor_cost_calculator(data=calldata)
        )
        return max(intrinsic_cost, transaction_floor_data_cost)

    return fn

blob_base_fee_update_fraction(*, block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction for Prague.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2926
2927
2928
2929
2930
2931
2932
@classmethod
def blob_base_fee_update_fraction(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Return the blob base fee update fraction for Prague."""
    del block_number, timestamp
    return 5007716

target_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in Prague, have a static target of 6 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2934
2935
2936
2937
2938
2939
2940
@classmethod
def target_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in Prague, have a static target of 6 blobs per block."""
    del block_number, timestamp
    return 6

max_blobs_per_block(*, block_number=0, timestamp=0) classmethod

Blobs in Prague, have a static max of 9 blobs per block.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2942
2943
2944
2945
2946
2947
2948
@classmethod
def max_blobs_per_block(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """Blobs in Prague, have a static max of 9 blobs per block."""
    del block_number, timestamp
    return 9

pre_allocation_blockchain(*, block_number=0, timestamp=0) classmethod

Prague requires pre-allocation of the beacon chain deposit contract for EIP-6110, the exits contract for EIP-7002, and the history storage contract for EIP-2935.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
@classmethod
def pre_allocation_blockchain(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Mapping:
    """
    Prague requires pre-allocation of the beacon chain deposit contract for
    EIP-6110, the exits contract for EIP-7002, and the history storage
    contract for EIP-2935.
    """
    del block_number, timestamp
    new_allocation = {}

    # Add the beacon chain deposit contract
    deposit_contract_tree_depth = 32
    storage = {}
    next_hash = sha256(b"\x00" * 64).digest()
    for i in range(
        deposit_contract_tree_depth + 2,
        deposit_contract_tree_depth * 2 + 1,
    ):
        storage[i] = next_hash
        next_hash = sha256(next_hash + next_hash).digest()

    with open(
        CURRENT_FOLDER / "contracts" / "deposit_contract.bin", mode="rb"
    ) as f:
        new_allocation.update(
            {
                0x00000000219AB540356CBB839CBE05303D7705FA: {
                    "nonce": 1,
                    "code": f.read(),
                    "storage": storage,
                }
            }
        )

    # EIP-7002: Add the withdrawal request contract
    with open(
        CURRENT_FOLDER / "contracts" / "withdrawal_request.bin", mode="rb"
    ) as f:
        new_allocation.update(
            {
                0x00000961EF480EB55E80D19AD83579A64C007002: {
                    "nonce": 1,
                    "code": f.read(),
                },
            }
        )

    # EIP-7251: Add the consolidation request contract
    with open(
        CURRENT_FOLDER / "contracts" / "consolidation_request.bin",
        mode="rb",
    ) as f:
        new_allocation.update(
            {
                0x0000BBDDC7CE488642FB579F8B00F3A590007251: {
                    "nonce": 1,
                    "code": f.read(),
                },
            }
        )

    # EIP-2935: Add the history storage contract
    with open(
        CURRENT_FOLDER / "contracts" / "history_contract.bin", mode="rb"
    ) as f:
        new_allocation.update(
            {
                0x0000F90827F1C53A10CB7A02335B175320002935: {
                    "nonce": 1,
                    "code": f.read(),
                }
            }
        )

    return new_allocation | super(Prague, cls).pre_allocation_blockchain()  # type: ignore

header_requests_required(*, block_number=0, timestamp=0) classmethod

Prague requires that the execution layer header contains the beacon chain requests hash.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
@classmethod
def header_requests_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """
    Prague requires that the execution layer header contains the beacon
    chain requests hash.
    """
    del block_number, timestamp
    return True

engine_new_payload_requests(*, block_number=0, timestamp=0) classmethod

From Prague, new payloads include the requests hash as a parameter.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3039
3040
3041
3042
3043
3044
3045
3046
3047
@classmethod
def engine_new_payload_requests(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """
    From Prague, new payloads include the requests hash as a parameter.
    """
    del block_number, timestamp
    return True

engine_new_payload_version(*, block_number=0, timestamp=0) classmethod

From Prague, new payload calls must use version 4.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3049
3050
3051
3052
3053
3054
3055
@classmethod
def engine_new_payload_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """From Prague, new payload calls must use version 4."""
    del block_number, timestamp
    return 4

engine_forkchoice_updated_version(*, block_number=0, timestamp=0) classmethod

At Prague, version number of NewPayload and ForkchoiceUpdated diverge.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
3057
3058
3059
3060
3061
3062
3063
3064
3065
@classmethod
def engine_forkchoice_updated_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """
    At Prague, version number of NewPayload and ForkchoiceUpdated diverge.
    """
    del block_number, timestamp
    return 3

Shanghai

Bases: Paris

Shanghai fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
class Shanghai(Paris):
    """Shanghai fork."""

    @classmethod
    def header_withdrawals_required(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> bool:
        """Withdrawals are required starting from Shanghai."""
        del block_number, timestamp
        return True

    @classmethod
    def engine_new_payload_version(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Optional[int]:
        """From Shanghai, new payload calls must use version 2."""
        del block_number, timestamp
        return 2

    @classmethod
    def max_initcode_size(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> int:
        """From Shanghai, the initcode size is now limited. See EIP-3860."""
        del block_number, timestamp
        return 0xC000

    @classmethod
    def _calculate_create_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """
        Calculate CREATE gas cost based on metadata (from Shanghai, includes
        initcode cost).
        """
        metadata = opcode.metadata

        # Get base cost from parent fork
        base_cost = super(Shanghai, cls)._calculate_create_gas(
            opcode, gas_costs
        )

        # Add initcode cost (EIP-3860)
        init_code_size = metadata["init_code_size"]
        init_code_words = (init_code_size + 31) // 32
        init_code_gas = gas_costs.G_INITCODE_WORD * init_code_words

        return base_cost + init_code_gas

    @classmethod
    def _calculate_create2_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """
        Calculate CREATE2 gas cost based on metadata (from Shanghai,
        includes initcode cost).
        """
        metadata = opcode.metadata

        # Get base cost from parent fork (includes keccak hash cost)
        base_cost = super(Shanghai, cls)._calculate_create2_gas(
            opcode, gas_costs
        )

        # Add initcode cost (EIP-3860)
        init_code_size = metadata["init_code_size"]
        init_code_words = (init_code_size + 31) // 32
        init_code_gas = gas_costs.G_INITCODE_WORD * init_code_words

        return base_cost + init_code_gas

    @classmethod
    def opcode_gas_map(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
        """Add Shanghai opcodes gas costs."""
        gas_costs = cls.gas_costs(
            block_number=block_number, timestamp=timestamp
        )
        base_map = super(Shanghai, cls).opcode_gas_map(
            block_number=block_number, timestamp=timestamp
        )
        return {
            **base_map,
            Opcodes.PUSH0: gas_costs.G_BASE,
        }

    @classmethod
    def valid_opcodes(
        cls, *, block_number: int = 0, timestamp: int = 0
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        del block_number, timestamp
        return [Opcodes.PUSH0] + super(Shanghai, cls).valid_opcodes()

header_withdrawals_required(*, block_number=0, timestamp=0) classmethod

Withdrawals are required starting from Shanghai.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2202
2203
2204
2205
2206
2207
2208
@classmethod
def header_withdrawals_required(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> bool:
    """Withdrawals are required starting from Shanghai."""
    del block_number, timestamp
    return True

engine_new_payload_version(*, block_number=0, timestamp=0) classmethod

From Shanghai, new payload calls must use version 2.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2210
2211
2212
2213
2214
2215
2216
@classmethod
def engine_new_payload_version(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
    """From Shanghai, new payload calls must use version 2."""
    del block_number, timestamp
    return 2

max_initcode_size(*, block_number=0, timestamp=0) classmethod

From Shanghai, the initcode size is now limited. See EIP-3860.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2218
2219
2220
2221
2222
2223
2224
@classmethod
def max_initcode_size(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> int:
    """From Shanghai, the initcode size is now limited. See EIP-3860."""
    del block_number, timestamp
    return 0xC000

opcode_gas_map(*, block_number=0, timestamp=0) classmethod

Add Shanghai opcodes gas costs.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
@classmethod
def opcode_gas_map(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> Dict[OpcodeBase, int | Callable[[OpcodeBase], int]]:
    """Add Shanghai opcodes gas costs."""
    gas_costs = cls.gas_costs(
        block_number=block_number, timestamp=timestamp
    )
    base_map = super(Shanghai, cls).opcode_gas_map(
        block_number=block_number, timestamp=timestamp
    )
    return {
        **base_map,
        Opcodes.PUSH0: gas_costs.G_BASE,
    }

valid_opcodes(*, block_number=0, timestamp=0) classmethod

Return list of Opcodes that are valid to work on this fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
2286
2287
2288
2289
2290
2291
2292
@classmethod
def valid_opcodes(
    cls, *, block_number: int = 0, timestamp: int = 0
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    del block_number, timestamp
    return [Opcodes.PUSH0] + super(Shanghai, cls).valid_opcodes()

SpuriousDragon

Bases: TangerineWhistle

SpuriousDragon fork.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
class SpuriousDragon(TangerineWhistle, ignore=True):
    """SpuriousDragon fork."""

    @classmethod
    def _calculate_call_gas(
        cls, opcode: OpcodeBase, gas_costs: GasCosts
    ) -> int:
        """
        At Spurious Dragon, the call gas cost needs to take the value transfer
        and account new into account.
        """
        base_cost = super(SpuriousDragon, cls)._calculate_call_gas(
            opcode, gas_costs
        )

        # Additional costs for value transfer, does not apply to STATICCALL
        metadata = opcode.metadata
        if "value_transfer" in metadata:
            if metadata["value_transfer"]:
                base_cost += gas_costs.G_CALL_VALUE
                if metadata["account_new"]:
                    base_cost += gas_costs.G_NEW_ACCOUNT
            elif metadata["account_new"]:
                raise ValueError("Account new requires value transfer")

        return base_cost

    @classmethod
    def supports_protected_txs(cls) -> bool:
        """
        At Genesis, supports EIP-155 protected transactions.
        """
        return True

supports_protected_txs() classmethod

At Genesis, supports EIP-155 protected transactions.

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1596
1597
1598
1599
1600
1601
@classmethod
def supports_protected_txs(cls) -> bool:
    """
    At Genesis, supports EIP-155 protected transactions.
    """
    return True

TangerineWhistle

Bases: DAOFork

TangerineWhistle fork (EIP-150).

Source code in packages/testing/src/execution_testing/forks/forks/forks.py
1563
1564
1565
1566
class TangerineWhistle(DAOFork, ignore=True):
    """TangerineWhistle fork (EIP-150)."""

    pass

BerlinToLondonAt5

Bases: Berlin

Berlin to London transition at Block 5.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
21
22
23
24
25
@transition_fork(to_fork=London, at_block=5)
class BerlinToLondonAt5(Berlin):
    """Berlin to London transition at Block 5."""

    pass

BPO1ToBPO2AtTime15k

Bases: BPO1

BPO1 to BPO2 transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
63
64
65
66
67
@transition_fork(to_fork=BPO2, at_timestamp=15_000)
class BPO1ToBPO2AtTime15k(BPO1):
    """BPO1 to BPO2 transition at Timestamp 15k."""

    pass

BPO2ToAmsterdamAtTime15k

Bases: BPO2

BPO2 to Amsterdam transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
70
71
72
73
74
75
76
77
78
@transition_fork(to_fork=Amsterdam, at_timestamp=15_000)
class BPO2ToAmsterdamAtTime15k(BPO2):
    """BPO2 to Amsterdam transition at Timestamp 15k."""

    # TODO: We may need to adjust which BPO Amsterdam inherits from as the
    #  related Amsterdam specs change over time, and before Amsterdam is
    #  live on mainnet.

    pass

BPO2ToBPO3AtTime15k

Bases: BPO2

BPO2 to BPO3 transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
81
82
83
84
85
@transition_fork(to_fork=BPO3, at_timestamp=15_000)
class BPO2ToBPO3AtTime15k(BPO2):
    """BPO2 to BPO3 transition at Timestamp 15k."""

    pass

BPO3ToBPO4AtTime15k

Bases: BPO3

BPO3 to BPO4 transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
88
89
90
91
92
@transition_fork(to_fork=BPO4, at_timestamp=15_000)
class BPO3ToBPO4AtTime15k(BPO3):
    """BPO3 to BPO4 transition at Timestamp 15k."""

    pass

CancunToPragueAtTime15k

Bases: Cancun

Cancun to Prague transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
42
43
44
45
46
@transition_fork(to_fork=Prague, at_timestamp=15_000)
class CancunToPragueAtTime15k(Cancun):
    """Cancun to Prague transition at Timestamp 15k."""

    pass

OsakaToBPO1AtTime15k

Bases: Osaka

Osaka to BPO1 transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
56
57
58
59
60
@transition_fork(to_fork=BPO1, at_timestamp=15_000)
class OsakaToBPO1AtTime15k(Osaka):
    """Osaka to BPO1 transition at Timestamp 15k."""

    pass

ParisToShanghaiAtTime15k

Bases: Paris

Paris to Shanghai transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
28
29
30
31
32
@transition_fork(to_fork=Shanghai, at_timestamp=15_000)
class ParisToShanghaiAtTime15k(Paris):
    """Paris to Shanghai transition at Timestamp 15k."""

    pass

PragueToOsakaAtTime15k

Bases: Prague

Prague to Osaka transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
49
50
51
52
53
@transition_fork(to_fork=Osaka, at_timestamp=15_000)
class PragueToOsakaAtTime15k(Prague):
    """Prague to Osaka transition at Timestamp 15k."""

    pass

ShanghaiToCancunAtTime15k

Bases: Shanghai

Shanghai to Cancun transition at Timestamp 15k.

Source code in packages/testing/src/execution_testing/forks/forks/transition.py
35
36
37
38
39
@transition_fork(to_fork=Cancun, at_timestamp=15_000)
class ShanghaiToCancunAtTime15k(Shanghai):
    """Shanghai to Cancun transition at Timestamp 15k."""

    pass

GasCosts dataclass

Class that contains the gas cost constants for any fork.

Source code in packages/testing/src/execution_testing/forks/gas_costs.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
@dataclass(kw_only=True, frozen=True)
class GasCosts:
    """Class that contains the gas cost constants for any fork."""

    G_JUMPDEST: int
    G_BASE: int
    G_VERY_LOW: int
    G_LOW: int
    G_MID: int
    G_HIGH: int
    G_WARM_ACCOUNT_ACCESS: int
    G_COLD_ACCOUNT_ACCESS: int
    G_ACCESS_LIST_ADDRESS: int
    G_ACCESS_LIST_STORAGE: int
    G_WARM_SLOAD: int
    G_COLD_SLOAD: int
    G_STORAGE_SET: int
    G_STORAGE_UPDATE: int
    G_STORAGE_RESET: int

    R_STORAGE_CLEAR: int

    G_SELF_DESTRUCT: int
    G_CREATE: int

    G_CODE_DEPOSIT_BYTE: int
    G_INITCODE_WORD: int

    G_CALL_VALUE: int
    G_CALL_STIPEND: int
    G_NEW_ACCOUNT: int

    G_EXP: int
    G_EXP_BYTE: int

    G_MEMORY: int

    G_TX_DATA_ZERO: int
    G_TX_DATA_NON_ZERO: int
    G_TX_DATA_STANDARD_TOKEN_COST: int
    G_TX_DATA_FLOOR_TOKEN_COST: int

    G_TRANSACTION: int
    G_TRANSACTION_CREATE: int

    G_LOG: int
    G_LOG_DATA: int
    G_LOG_TOPIC: int

    G_KECCAK_256: int
    G_KECCAK_256_WORD: int

    G_COPY: int
    G_BLOCKHASH: int

    G_AUTHORIZATION: int

    # Precompiled contract gas constants

    G_PRECOMPILE_ECRECOVER: int
    G_PRECOMPILE_SHA256_BASE: int
    G_PRECOMPILE_SHA256_WORD: int
    G_PRECOMPILE_RIPEMD160_BASE: int
    G_PRECOMPILE_RIPEMD160_WORD: int
    G_PRECOMPILE_IDENTITY_BASE: int
    G_PRECOMPILE_IDENTITY_WORD: int

    G_PRECOMPILE_ECADD: int
    G_PRECOMPILE_ECMUL: int
    G_PRECOMPILE_ECPAIRING_BASE: int
    G_PRECOMPILE_ECPAIRING_PER_POINT: int

    G_PRECOMPILE_BLAKE2F_BASE: int
    G_PRECOMPILE_BLAKE2F_PER_ROUND: int

    G_PRECOMPILE_POINT_EVALUATION: int

    G_PRECOMPILE_BLS_G1ADD: int
    G_PRECOMPILE_BLS_G1MUL: int
    G_PRECOMPILE_BLS_G1MAP: int
    G_PRECOMPILE_BLS_G2ADD: int
    G_PRECOMPILE_BLS_G2MUL: int
    G_PRECOMPILE_BLS_G2MAP: int
    G_PRECOMPILE_BLS_PAIRING_BASE: int
    G_PRECOMPILE_BLS_PAIRING_PER_PAIR: int

    G_PRECOMPILE_P256VERIFY: int

    # Refund constants

    R_AUTHORIZATION_EXISTING_AUTHORITY: int

ForkRangeDescriptor

Bases: BaseModel

Fork descriptor parsed from string normally contained in ethereum/tests fillers.

Source code in packages/testing/src/execution_testing/forks/helpers.py
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
class ForkRangeDescriptor(BaseModel):
    """
    Fork descriptor parsed from string normally contained in ethereum/tests
    fillers.
    """

    greater_equal: Type[BaseFork] | None = None
    less_than: Type[BaseFork] | None = None
    model_config = ConfigDict(frozen=True)

    def fork_in_range(self, fork: Type[BaseFork]) -> bool:
        """Return whether the given fork is within range."""
        if self.greater_equal is not None and fork < self.greater_equal:
            return False
        if self.less_than is not None and fork >= self.less_than:
            return False
        return True

    @model_validator(mode="wrap")
    @classmethod
    def validate_fork_range_descriptor(
        cls, v: Any, handler: ValidatorFunctionWrapHandler
    ) -> "ForkRangeDescriptor":
        """
        Validate the fork range descriptor from a string.

        Examples:
          - ">=Osaka" validates to {greater_equal=Osaka, less_than=None}

          - ">=Prague<Osaka" validates to {greater_equal=Prague,
                                           less_than=Osaka}

        """
        if isinstance(v, str):
            # Decompose the string into its parts
            descriptor_string = re.sub(r"\s+", "", v.strip())
            v = {}
            if m := re.search(r">=(\w+)", descriptor_string):
                fork: Type[BaseFork] | None = get_fork_by_name(m.group(1))
                if fork is None:
                    raise Exception(f"Unable to parse fork name: {m.group(1)}")
                v["greater_equal"] = fork
                descriptor_string = re.sub(r">=(\w+)", "", descriptor_string)
            if m := re.search(r"<(\w+)", descriptor_string):
                fork = get_fork_by_name(m.group(1))
                if fork is None:
                    raise Exception(f"Unable to parse fork name: {m.group(1)}")
                v["less_than"] = fork
                descriptor_string = re.sub(r"<(\w+)", "", descriptor_string)
            if descriptor_string:
                raise Exception(
                    "Unable to completely parse fork range descriptor. "
                    + f'Remaining string: "{descriptor_string}"'
                )
        return handler(v)

fork_in_range(fork)

Return whether the given fork is within range.

Source code in packages/testing/src/execution_testing/forks/helpers.py
344
345
346
347
348
349
350
def fork_in_range(self, fork: Type[BaseFork]) -> bool:
    """Return whether the given fork is within range."""
    if self.greater_equal is not None and fork < self.greater_equal:
        return False
    if self.less_than is not None and fork >= self.less_than:
        return False
    return True

validate_fork_range_descriptor(v, handler) classmethod

Validate the fork range descriptor from a string.

Examples:

  • ">=Osaka" validates to {greater_equal=Osaka, less_than=None}

  • ">=Prague

Source code in packages/testing/src/execution_testing/forks/helpers.py
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
@model_validator(mode="wrap")
@classmethod
def validate_fork_range_descriptor(
    cls, v: Any, handler: ValidatorFunctionWrapHandler
) -> "ForkRangeDescriptor":
    """
    Validate the fork range descriptor from a string.

    Examples:
      - ">=Osaka" validates to {greater_equal=Osaka, less_than=None}

      - ">=Prague<Osaka" validates to {greater_equal=Prague,
                                       less_than=Osaka}

    """
    if isinstance(v, str):
        # Decompose the string into its parts
        descriptor_string = re.sub(r"\s+", "", v.strip())
        v = {}
        if m := re.search(r">=(\w+)", descriptor_string):
            fork: Type[BaseFork] | None = get_fork_by_name(m.group(1))
            if fork is None:
                raise Exception(f"Unable to parse fork name: {m.group(1)}")
            v["greater_equal"] = fork
            descriptor_string = re.sub(r">=(\w+)", "", descriptor_string)
        if m := re.search(r"<(\w+)", descriptor_string):
            fork = get_fork_by_name(m.group(1))
            if fork is None:
                raise Exception(f"Unable to parse fork name: {m.group(1)}")
            v["less_than"] = fork
            descriptor_string = re.sub(r"<(\w+)", "", descriptor_string)
        if descriptor_string:
            raise Exception(
                "Unable to completely parse fork range descriptor. "
                + f'Remaining string: "{descriptor_string}"'
            )
    return handler(v)

InvalidForkError

Bases: Exception

Invalid fork error raised when the fork specified is not found or incompatible.

Source code in packages/testing/src/execution_testing/forks/helpers.py
31
32
33
34
35
36
37
38
39
class InvalidForkError(Exception):
    """
    Invalid fork error raised when the fork specified is not found or
    incompatible.
    """

    def __init__(self, message: str) -> None:
        """Initialize the InvalidForkError exception."""
        super().__init__(message)

__init__(message)

Initialize the InvalidForkError exception.

Source code in packages/testing/src/execution_testing/forks/helpers.py
37
38
39
def __init__(self, message: str) -> None:
    """Initialize the InvalidForkError exception."""
    super().__init__(message)

forks_from(fork, deployed_only=True)

Return specified fork and all forks after it.

Source code in packages/testing/src/execution_testing/forks/helpers.py
282
283
284
285
286
287
288
289
290
def forks_from(
    fork: Type[BaseFork], deployed_only: bool = True
) -> List[Type[BaseFork]]:
    """Return specified fork and all forks after it."""
    if deployed_only:
        latest_fork = get_deployed_forks()[-1]
    else:
        latest_fork = get_forks()[-1]
    return forks_from_until(fork, latest_fork)

forks_from_until(fork_from, fork_until)

Return specified fork and all forks after it until and including the second specified fork.

Source code in packages/testing/src/execution_testing/forks/helpers.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
def forks_from_until(
    fork_from: Type[BaseFork], fork_until: Type[BaseFork]
) -> List[Type[BaseFork]]:
    """
    Return specified fork and all forks after it until and including the second
    specified fork.
    """
    prev_fork = fork_until

    forks: List[Type[BaseFork]] = []

    while prev_fork != BaseFork and prev_fork != fork_from:
        forks.insert(0, prev_fork)

        prev_fork = get_parent_fork(prev_fork)

    if prev_fork == BaseFork:
        return []

    forks.insert(0, fork_from)

    return forks

get_closest_fork(fork)

Return None if BaseFork is passed, otherwise return the fork itself.

Source code in packages/testing/src/execution_testing/forks/helpers.py
107
108
109
110
111
def get_closest_fork(fork: Type[BaseFork]) -> Optional[Type[BaseFork]]:
    """Return None if BaseFork is passed, otherwise return the fork itself."""
    if fork is BaseFork:
        return None
    return fork

get_deployed_forks()

Return all fork classes that have been deployed to mainnet.

Chronologically ordered by deployment. BPO (Blob Parameter Only) forks are excluded as they are handled separately.

Source code in packages/testing/src/execution_testing/forks/helpers.py
76
77
78
79
80
81
82
83
84
85
86
87
def get_deployed_forks() -> List[Type[BaseFork]]:
    """
    Return all fork classes that have been deployed to mainnet.

    Chronologically ordered by deployment. BPO (Blob Parameter Only) forks
    are excluded as they are handled separately.
    """
    return [
        fork
        for fork in get_forks()
        if fork.is_deployed() and not fork.ignore() and not fork.bpo_fork()
    ]

get_development_forks()

Return all fork classes not yet deployed and under development.

The list is ordered by their planned deployment date.

Source code in packages/testing/src/execution_testing/forks/helpers.py
90
91
92
93
94
95
96
def get_development_forks() -> List[Type[BaseFork]]:
    """
    Return all fork classes not yet deployed and under development.

    The list is ordered by their planned deployment date.
    """
    return [fork for fork in get_forks() if not fork.is_deployed()]

get_fork_by_name(fork_name)

Get a fork by name.

Source code in packages/testing/src/execution_testing/forks/helpers.py
326
327
328
329
330
331
def get_fork_by_name(fork_name: str) -> Type[BaseFork] | None:
    """Get a fork by name."""
    for fork in get_forks():
        if fork.name() == fork_name:
            return fork
    return None

get_forks()

Return all fork classes implemented by execution_testing.forks.

Ordered chronologically by deployment.

Source code in packages/testing/src/execution_testing/forks/helpers.py
67
68
69
70
71
72
73
def get_forks() -> List[Type[BaseFork]]:
    """
    Return all fork classes implemented by `execution_testing.forks`.

    Ordered chronologically by deployment.
    """
    return all_forks[:]

get_forks_with_no_descendants(forks)

Get forks with no descendants in the inheritance hierarchy.

Source code in packages/testing/src/execution_testing/forks/helpers.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def get_forks_with_no_descendants(
    forks: Set[Type[BaseFork]],
) -> Set[Type[BaseFork]]:
    """Get forks with no descendants in the inheritance hierarchy."""
    resulting_forks: Set[Type[BaseFork]] = set()
    for fork in forks:
        descendants = False
        for next_fork in forks - {fork}:
            if next_fork > fork:
                descendants = True
                break
        if not descendants:
            resulting_forks = resulting_forks | {fork}
    return resulting_forks

get_forks_with_no_parents(forks)

Get forks with no parents in the inheritance hierarchy.

Source code in packages/testing/src/execution_testing/forks/helpers.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def get_forks_with_no_parents(
    forks: Set[Type[BaseFork]] | FrozenSet[Type[BaseFork]],
) -> Set[Type[BaseFork]]:
    """Get forks with no parents in the inheritance hierarchy."""
    resulting_forks: Set[Type[BaseFork]] = set()
    for fork in forks:
        parents = False
        for next_fork in forks - {fork}:
            if next_fork < fork:
                parents = True
                break
        if not parents:
            resulting_forks = resulting_forks | {fork}
    return resulting_forks

get_from_until_fork_set(forks, forks_from, forks_until)

Get fork range from forks_from to forks_until.

Source code in packages/testing/src/execution_testing/forks/helpers.py
137
138
139
140
141
142
143
144
145
146
147
148
149
def get_from_until_fork_set(
    forks: Set[Type[BaseFork]] | FrozenSet[Type[BaseFork]],
    forks_from: Set[Type[BaseFork]],
    forks_until: Set[Type[BaseFork]],
) -> Set[Type[BaseFork]]:
    """Get fork range from forks_from to forks_until."""
    resulting_set = set()
    for fork_from in forks_from:
        for fork_until in forks_until:
            for fork in forks:
                if fork <= fork_until and fork >= fork_from:
                    resulting_set.add(fork)
    return resulting_set

get_last_descendants(forks, forks_from)

Get last descendant of a class in the inheritance hierarchy.

Source code in packages/testing/src/execution_testing/forks/helpers.py
184
185
186
187
188
189
190
191
192
193
194
def get_last_descendants(
    forks: Set[Type[BaseFork]], forks_from: Set[Type[BaseFork]]
) -> Set[Type[BaseFork]]:
    """Get last descendant of a class in the inheritance hierarchy."""
    resulting_forks: Set[Type[BaseFork]] = set()
    forks = get_forks_with_no_descendants(forks)
    for fork_from in forks_from:
        for fork in forks:
            if fork >= fork_from:
                resulting_forks = resulting_forks | {fork}
    return resulting_forks

get_relative_fork_markers(fork_identifier, strict_mode=True)

Return a list of marker names for a given fork.

For a base fork (e.g. Shanghai), return [ Shanghai ]. For a transition fork (e.g. ShanghaiToCancunAtTime15k which transitions to Cancun), return [ ShanghaiToCancunAtTime15k, Cancun ].

If strict_mode is set to True, raise an InvalidForkError if the fork is not found, otherwise, simply return the provided (str) fork_identifier (this is required to run consume with forks that are unknown to EEST).

Source code in packages/testing/src/execution_testing/forks/helpers.py
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
def get_relative_fork_markers(
    fork_identifier: Type[BaseFork] | str, strict_mode: bool = True
) -> list[str]:
    """
    Return a list of marker names for a given fork.

    For a base fork (e.g. `Shanghai`), return [ `Shanghai` ]. For a transition
    fork (e.g. `ShanghaiToCancunAtTime15k` which transitions to `Cancun`),
    return [ `ShanghaiToCancunAtTime15k`, `Cancun` ].

    If `strict_mode` is set to `True`, raise an `InvalidForkError` if the fork
    is not found, otherwise, simply return the provided (str) `fork_identifier`
    (this is required to run `consume` with forks that are unknown to EEST).
    """
    all_forks = set(get_forks()) | set(get_transition_forks())
    if isinstance(fork_identifier, str):
        fork_class = None
        for candidate in all_forks:
            if candidate.name() == fork_identifier:
                fork_class = candidate
                break
        if strict_mode and fork_class is None:
            raise InvalidForkError(f"Unknown fork: {fork_identifier}")
        return [fork_identifier]
    else:
        fork_class = fork_identifier

    if issubclass(fork_class, TransitionBaseClass):
        return [fork_class.name(), fork_class.transitions_to().name()]
    else:
        return [fork_class.name()]

get_selected_fork_set(*, single_fork, forks_from, forks_until, transition_forks=True)

Process sets derived from --fork, --until and --from to return an unified fork set.

Source code in packages/testing/src/execution_testing/forks/helpers.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
def get_selected_fork_set(
    *,
    single_fork: Set[Type[BaseFork]],
    forks_from: Set[Type[BaseFork]],
    forks_until: Set[Type[BaseFork]],
    transition_forks: bool = True,
) -> Set[Type[BaseFork]]:
    """
    Process sets derived from `--fork`, `--until` and `--from` to return an
    unified fork set.
    """
    selected_fork_set = set()
    if single_fork:
        selected_fork_set |= single_fork
    else:
        if not forks_from:
            forks_from = get_forks_with_no_parents(ALL_FORKS)
        if not forks_until:
            forks_until = get_last_descendants(
                set(get_deployed_forks()), forks_from
            )
        selected_fork_set = get_from_until_fork_set(
            ALL_FORKS, forks_from, forks_until
        )
    if transition_forks:
        for fork in list(selected_fork_set):
            transition_fork_set = transition_fork_to(fork)
            selected_fork_set |= transition_fork_set
    return selected_fork_set

get_transition_fork_predecessor(transition_fork)

Return the fork from which the transition fork transitions.

Source code in packages/testing/src/execution_testing/forks/helpers.py
119
120
121
122
123
124
125
def get_transition_fork_predecessor(
    transition_fork: Type[BaseFork],
) -> Type[BaseFork]:
    """Return the fork from which the transition fork transitions."""
    if not issubclass(transition_fork, TransitionBaseClass):
        raise InvalidForkError(f"{transition_fork} is not a transition fork.")
    return transition_fork.transitions_from()

get_transition_fork_successor(transition_fork)

Return the fork to which the transition fork transitions.

Source code in packages/testing/src/execution_testing/forks/helpers.py
128
129
130
131
132
133
134
def get_transition_fork_successor(
    transition_fork: Type[BaseFork],
) -> Type[BaseFork]:
    """Return the fork to which the transition fork transitions."""
    if not issubclass(transition_fork, TransitionBaseClass):
        raise InvalidForkError(f"{transition_fork} is not a transition fork.")
    return transition_fork.transitions_to()

get_transition_forks()

Return all the transition forks.

Source code in packages/testing/src/execution_testing/forks/helpers.py
114
115
116
def get_transition_forks() -> Set[Type[BaseFork]]:
    """Return all the transition forks."""
    return set(ALL_TRANSITION_FORKS)

transition_fork_from_to(fork_from, fork_to)

Return transition fork that transitions to and from the specified forks.

Source code in packages/testing/src/execution_testing/forks/helpers.py
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def transition_fork_from_to(
    fork_from: Type[BaseFork], fork_to: Type[BaseFork]
) -> Type[BaseFork] | None:
    """
    Return transition fork that transitions to and from the specified forks.
    """
    for transition_fork in get_transition_forks():
        if not issubclass(transition_fork, TransitionBaseClass):
            continue
        if (
            transition_fork.transitions_to() == fork_to
            and transition_fork.transitions_from() == fork_from
        ):
            return transition_fork

    return None

transition_fork_to(fork_to)

Return transition fork that transitions to the specified fork.

Source code in packages/testing/src/execution_testing/forks/helpers.py
246
247
248
249
250
251
252
253
254
255
def transition_fork_to(fork_to: Type[BaseFork]) -> Set[Type[BaseFork]]:
    """Return transition fork that transitions to the specified fork."""
    transition_forks: Set[Type[BaseFork]] = set()
    for transition_fork in get_transition_forks():
        if not issubclass(transition_fork, TransitionBaseClass):
            continue
        if transition_fork.transitions_to() == fork_to:
            transition_forks.add(transition_fork)

    return transition_forks