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 src/ethereum_test_forks/base_fork.py
28
29
30
31
32
33
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 src/ethereum_test_forks/base_fork.py
31
32
33
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

BPO1 fork - Blob Parameter Only fork 1.

Source code in src/ethereum_test_forks/forks/forks.py
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
class BPO1(Osaka, bpo_fork=True):
    """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."""
        return 8832827

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

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

blob_base_fee_update_fraction(block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction for BPO1.

Source code in src/ethereum_test_forks/forks/forks.py
1732
1733
1734
1735
@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."""
    return 8832827

target_blobs_per_block(block_number=0, timestamp=0) classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
1737
1738
1739
1740
@classmethod
def target_blobs_per_block(cls, block_number: int = 0, timestamp: int = 0) -> int:
    """Blobs in BPO1 have a target of 9 blobs per block."""
    return 9

max_blobs_per_block(block_number=0, timestamp=0) classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
1742
1743
1744
1745
@classmethod
def max_blobs_per_block(cls, block_number: int = 0, timestamp: int = 0) -> int:
    """Blobs in BPO1 have a max of 14 blobs per block."""
    return 14

BPO2

Bases: BPO1

BPO2 fork - Blob Parameter Only fork 2.

Source code in src/ethereum_test_forks/forks/forks.py
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
class BPO2(BPO1, bpo_fork=True):
    """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."""
        return 13739630

    @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."""
        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."""
        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 src/ethereum_test_forks/forks/forks.py
1751
1752
1753
1754
@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."""
    return 13739630

target_blobs_per_block(block_number=0, timestamp=0) classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
1756
1757
1758
1759
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1761
1762
1763
1764
@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."""
    return 21

BPO3

Bases: BPO2

BPO3 fork - Blob Parameter Only fork 3.

Source code in src/ethereum_test_forks/forks/forks.py
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
class BPO3(BPO2, bpo_fork=True):
    """BPO3 fork - Blob Parameter Only fork 3."""

    @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."""
        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."""
        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."""
        return 32

blob_base_fee_update_fraction(block_number=0, timestamp=0) classmethod

Return the blob base fee update fraction for BPO3.

Source code in src/ethereum_test_forks/forks/forks.py
1770
1771
1772
1773
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1775
1776
1777
1778
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1780
1781
1782
1783
@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."""
    return 32

BPO4

Bases: BPO3

BPO4 fork - Blob Parameter Only fork 4.

Source code in src/ethereum_test_forks/forks/forks.py
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
class BPO4(BPO3, bpo_fork=True):
    """BPO4 fork - Blob Parameter Only fork 4."""

    @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."""
        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."""
        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."""
        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 src/ethereum_test_forks/forks/forks.py
1789
1790
1791
1792
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1794
1795
1796
1797
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1799
1800
1801
1802
@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."""
    return 21

BPO5

Bases: BPO4

BPO5 fork - Blob Parameter Only fork 5 (Required to parse Fusaka devnet genesis files).

Source code in src/ethereum_test_forks/forks/forks.py
1805
1806
1807
1808
class BPO5(BPO4, bpo_fork=True):
    """BPO5 fork - Blob Parameter Only fork 5 (Required to parse Fusaka devnet genesis files)."""

    pass

Amsterdam

Bases: Osaka

Amsterdam fork.

Source code in src/ethereum_test_forks/forks/forks.py
1842
1843
1844
1845
1846
1847
1848
class Amsterdam(Osaka):
    """Amsterdam fork."""

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

is_deployed() classmethod

Return True if this fork is deployed.

Source code in src/ethereum_test_forks/forks/forks.py
1845
1846
1847
1848
@classmethod
def is_deployed(cls) -> bool:
    """Return True if this fork is deployed."""
    return False

ArrowGlacier

Bases: London

Arrow Glacier fork.

Source code in src/ethereum_test_forks/forks/forks.py
1046
1047
1048
1049
class ArrowGlacier(London, solc_name="london", ignore=True):
    """Arrow Glacier fork."""

    pass

Berlin

Bases: Istanbul

Berlin fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
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, 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, 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, timestamp
        )
        gas_costs = cls.gas_costs(block_number, 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,
                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 src/ethereum_test_forks/forks/forks.py
843
844
845
846
@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, timestamp)

contract_creating_tx_types(block_number=0, timestamp=0) classmethod

At Berlin, access list transactions are introduced.

Source code in src/ethereum_test_forks/forks/forks.py
848
849
850
851
@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, 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 src/ethereum_test_forks/forks/forks.py
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
@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, timestamp
    )
    gas_costs = cls.gas_costs(block_number, 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,
            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: Homestead

Byzantium fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
class Byzantium(Homestead):
    """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.
        """
        return 3_000_000_000_000_000_000

    @classmethod
    def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
        """
        At Byzantium, pre-compiles 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, timestamp)

    @classmethod
    def max_code_size(cls) -> 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."""
        return 0x6000

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

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

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 src/ethereum_test_forks/forks/forks.py
714
715
716
717
718
719
720
@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.
    """
    return 3_000_000_000_000_000_000

precompiles(block_number=0, timestamp=0) classmethod

At Byzantium, pre-compiles 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 src/ethereum_test_forks/forks/forks.py
722
723
724
725
726
727
728
729
730
731
732
733
734
@classmethod
def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """
    At Byzantium, pre-compiles 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, timestamp)

max_code_size() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
736
737
738
739
740
@classmethod
def max_code_size(cls) -> 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."""
    return 0x6000

call_opcodes(block_number=0, timestamp=0) classmethod

At Byzantium, STATICCALL opcode was introduced.

Source code in src/ethereum_test_forks/forks/forks.py
742
743
744
745
746
747
748
749
@classmethod
def call_opcodes(
    cls, block_number: int = 0, timestamp: int = 0
) -> List[Tuple[Opcodes, EVMCodeType]]:
    """At Byzantium, STATICCALL opcode was introduced."""
    return [(Opcodes.STATICCALL, EVMCodeType.LEGACY)] + super(Byzantium, cls).call_opcodes(
        block_number, timestamp
    )

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
751
752
753
754
755
756
757
758
759
760
761
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    return [
        Opcodes.REVERT,
        Opcodes.RETURNDATASIZE,
        Opcodes.RETURNDATACOPY,
        Opcodes.STATICCALL,
    ] + super(Byzantium, cls).valid_opcodes()

Cancun

Bases: Shanghai

Cancun fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
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,
        "BLS_MODULUS": 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001,  # EIP-2537: Main subgroup order = q, due to this BLS_MODULUS every blob byte (uint256) must be smaller than 116  # noqa: E501
        # 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."""
        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."""
        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."""
        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, timestamp)
        blob_base_fee_update_fraction = cls.blob_base_fee_update_fraction(block_number, timestamp)

        def fn(*, excess_blob_gas) -> 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, timestamp)
        blob_gas_per_blob = cls.blob_gas_per_blob(block_number, 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,
            parent_base_fee_per_gas: int,  # Required for Osaka as using this as base
        ) -> 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
            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."""
        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."""
        return 3338477

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

    @classmethod
    def supports_blobs(cls, block_number: int = 0, timestamp: int = 0) -> bool:
        """At Cancun, blobs support is enabled."""
        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."""
        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."""
        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."""
        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."""
        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, 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, timestamp) or BlobSchedule()
        current_blob_schedule = ForkBlobSchedule(
            target_blobs_per_block=cls.target_blobs_per_block(block_number, timestamp),
            max_blobs_per_block=cls.max_blobs_per_block(block_number, timestamp),
            base_fee_update_fraction=cls.blob_base_fee_update_fraction(block_number, 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, timestamp)

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

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

    @classmethod
    def pre_allocation_blockchain(cls) -> Mapping:
        """
        Cancun requires pre-allocation of the beacon root contract for EIP-4788 on blockchain
        type tests.
        """
        new_allocation = {
            0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02: {
                "nonce": 1,
                "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5f"
                "fd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f"
                "5ffd5b62001fff42064281555f359062001fff015500",
            }
        }
        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."""
        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."""
        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."""
        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."""
        return True

    @classmethod
    def valid_opcodes(
        cls,
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        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 src/ethereum_test_forks/forks/forks.py
1130
1131
1132
1133
1134
1135
1136
1137
@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 src/ethereum_test_forks/forks/forks.py
1139
1140
1141
1142
@classmethod
def header_excess_blob_gas_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Excess blob gas is required starting from Cancun."""
    return True

header_blob_gas_used_required(block_number=0, timestamp=0) classmethod

Blob gas used is required starting from Cancun.

Source code in src/ethereum_test_forks/forks/forks.py
1144
1145
1146
1147
@classmethod
def header_blob_gas_used_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Blob gas used is required starting from Cancun."""
    return True

header_beacon_root_required(block_number=0, timestamp=0) classmethod

Parent beacon block root is required starting from Cancun.

Source code in src/ethereum_test_forks/forks/forks.py
1149
1150
1151
1152
@classmethod
def header_beacon_root_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Parent beacon block root is required starting from Cancun."""
    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 src/ethereum_test_forks/forks/forks.py
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
@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, timestamp)
    blob_base_fee_update_fraction = cls.blob_base_fee_update_fraction(block_number, timestamp)

    def fn(*, excess_blob_gas) -> 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 src/ethereum_test_forks/forks/forks.py
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
@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, timestamp)
    blob_gas_per_blob = cls.blob_gas_per_blob(block_number, 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,
        parent_base_fee_per_gas: int,  # Required for Osaka as using this as base
    ) -> 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
        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 src/ethereum_test_forks/forks/forks.py
1201
1202
1203
1204
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1206
1207
1208
1209
@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."""
    return 3338477

blob_gas_per_blob(block_number=0, timestamp=0) classmethod

Blobs are enabled starting from Cancun.

Source code in src/ethereum_test_forks/forks/forks.py
1211
1212
1213
1214
@classmethod
def blob_gas_per_blob(cls, block_number: int = 0, timestamp: int = 0) -> int:
    """Blobs are enabled starting from Cancun."""
    return 2**17

supports_blobs(block_number=0, timestamp=0) classmethod

At Cancun, blobs support is enabled.

Source code in src/ethereum_test_forks/forks/forks.py
1216
1217
1218
1219
@classmethod
def supports_blobs(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """At Cancun, blobs support is enabled."""
    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 src/ethereum_test_forks/forks/forks.py
1221
1222
1223
1224
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1226
1227
1228
1229
@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."""
    return 6

blob_reserve_price_active(block_number=0, timestamp=0) classmethod

Blob reserve price is not supported in Cancun.

Source code in src/ethereum_test_forks/forks/forks.py
1231
1232
1233
1234
@classmethod
def blob_reserve_price_active(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Blob reserve price is not supported in Cancun."""
    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 src/ethereum_test_forks/forks/forks.py
1236
1237
1238
1239
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1241
1242
1243
1244
@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, 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 src/ethereum_test_forks/forks/forks.py
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
@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, timestamp) or BlobSchedule()
    current_blob_schedule = ForkBlobSchedule(
        target_blobs_per_block=cls.target_blobs_per_block(block_number, timestamp),
        max_blobs_per_block=cls.max_blobs_per_block(block_number, timestamp),
        base_fee_update_fraction=cls.blob_base_fee_update_fraction(block_number, 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 src/ethereum_test_forks/forks/forks.py
1263
1264
1265
1266
@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, timestamp)

precompiles(block_number=0, timestamp=0) classmethod

At Cancun, pre-compile for kzg point evaluation is introduced.

Source code in src/ethereum_test_forks/forks/forks.py
1268
1269
1270
1271
1272
1273
@classmethod
def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """At Cancun, pre-compile for kzg point evaluation is introduced."""
    return [
        Address(10, label="KZG_POINT_EVALUATION"),
    ] + super(Cancun, cls).precompiles(block_number, timestamp)

system_contracts(block_number=0, timestamp=0) classmethod

Cancun introduces the system contract for EIP-4788.

Source code in src/ethereum_test_forks/forks/forks.py
1275
1276
1277
1278
@classmethod
def system_contracts(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """Cancun introduces the system contract for EIP-4788."""
    return [Address(0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02, label="BEACON_ROOTS_ADDRESS")]

pre_allocation_blockchain() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
@classmethod
def pre_allocation_blockchain(cls) -> Mapping:
    """
    Cancun requires pre-allocation of the beacon root contract for EIP-4788 on blockchain
    type tests.
    """
    new_allocation = {
        0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02: {
            "nonce": 1,
            "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5f"
            "fd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f"
            "5ffd5b62001fff42064281555f359062001fff015500",
        }
    }
    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 src/ethereum_test_forks/forks/forks.py
1296
1297
1298
1299
1300
1301
@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."""
    return 3

engine_get_blobs_version(block_number=0, timestamp=0) classmethod

At Cancun, the engine get blobs version is 1.

Source code in src/ethereum_test_forks/forks/forks.py
1303
1304
1305
1306
@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."""
    return 1

engine_new_payload_blob_hashes(block_number=0, timestamp=0) classmethod

From Cancun, payloads must have blob hashes.

Source code in src/ethereum_test_forks/forks/forks.py
1308
1309
1310
1311
@classmethod
def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """From Cancun, payloads must have blob hashes."""
    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 src/ethereum_test_forks/forks/forks.py
1313
1314
1315
1316
@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."""
    return True

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    return [
        Opcodes.BLOBHASH,
        Opcodes.BLOBBASEFEE,
        Opcodes.TLOAD,
        Opcodes.TSTORE,
        Opcodes.MCOPY,
    ] + super(Cancun, cls).valid_opcodes()

Constantinople

Bases: Byzantium

Constantinople fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
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.
        """
        return 2_000_000_000_000_000_000

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

    @classmethod
    def valid_opcodes(
        cls,
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        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 src/ethereum_test_forks/forks/forks.py
767
768
769
770
771
772
773
@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.
    """
    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 src/ethereum_test_forks/forks/forks.py
775
776
777
778
779
780
781
782
@classmethod
def create_opcodes(
    cls, block_number: int = 0, timestamp: int = 0
) -> List[Tuple[Opcodes, EVMCodeType]]:
    """At Constantinople, `CREATE2` opcode is added."""
    return [(Opcodes.CREATE2, EVMCodeType.LEGACY)] + super(Constantinople, cls).create_opcodes(
        block_number, timestamp
    )

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
784
785
786
787
788
789
790
791
792
793
794
795
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    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 src/ethereum_test_forks/forks/forks.py
798
799
800
801
class ConstantinopleFix(Constantinople, solc_name="constantinople"):
    """Constantinople Fix fork."""

    pass

EOFv1

Bases: Prague

EOF fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
class EOFv1(Prague, solc_name="cancun"):
    """EOF fork."""

    @classmethod
    def evm_code_types(cls, block_number: int = 0, timestamp: int = 0) -> List[EVMCodeType]:
        """EOF V1 is supported starting from Osaka."""
        return super(EOFv1, cls).evm_code_types(
            block_number,
            timestamp,
        ) + [EVMCodeType.EOF_V1]

    @classmethod
    def call_opcodes(
        cls, block_number: int = 0, timestamp: int = 0
    ) -> List[Tuple[Opcodes, EVMCodeType]]:
        """EOF V1 introduces EXTCALL, EXTSTATICCALL, EXTDELEGATECALL."""
        return [
            (Opcodes.EXTCALL, EVMCodeType.EOF_V1),
            (Opcodes.EXTSTATICCALL, EVMCodeType.EOF_V1),
            (Opcodes.EXTDELEGATECALL, EVMCodeType.EOF_V1),
        ] + super(EOFv1, cls).call_opcodes(block_number, timestamp)

    @classmethod
    def is_deployed(cls) -> bool:
        """
        Flag that the fork has not been deployed to mainnet; it is under active
        development.
        """
        return False

evm_code_types(block_number=0, timestamp=0) classmethod

EOF V1 is supported starting from Osaka.

Source code in src/ethereum_test_forks/forks/forks.py
1814
1815
1816
1817
1818
1819
1820
@classmethod
def evm_code_types(cls, block_number: int = 0, timestamp: int = 0) -> List[EVMCodeType]:
    """EOF V1 is supported starting from Osaka."""
    return super(EOFv1, cls).evm_code_types(
        block_number,
        timestamp,
    ) + [EVMCodeType.EOF_V1]

call_opcodes(block_number=0, timestamp=0) classmethod

EOF V1 introduces EXTCALL, EXTSTATICCALL, EXTDELEGATECALL.

Source code in src/ethereum_test_forks/forks/forks.py
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
@classmethod
def call_opcodes(
    cls, block_number: int = 0, timestamp: int = 0
) -> List[Tuple[Opcodes, EVMCodeType]]:
    """EOF V1 introduces EXTCALL, EXTSTATICCALL, EXTDELEGATECALL."""
    return [
        (Opcodes.EXTCALL, EVMCodeType.EOF_V1),
        (Opcodes.EXTSTATICCALL, EVMCodeType.EOF_V1),
        (Opcodes.EXTDELEGATECALL, EVMCodeType.EOF_V1),
    ] + super(EOFv1, cls).call_opcodes(block_number, timestamp)

is_deployed() classmethod

Flag that the fork has not been deployed to mainnet; it is under active development.

Source code in src/ethereum_test_forks/forks/forks.py
1833
1834
1835
1836
1837
1838
1839
@classmethod
def is_deployed(cls) -> bool:
    """
    Flag that the fork has not been deployed to mainnet; it is under active
    development.
    """
    return False

Frontier

Bases: BaseFork

Frontier fork.

Source code in src/ethereum_test_forks/forks/forks.py
 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
 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
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."""
        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."""
        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."""
        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."""
        return False

    @classmethod
    def header_withdrawals_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
        """At genesis, header must not contain withdrawals."""
        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."""
        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."""
        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."""
        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_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_TX_DATA_STANDARD_TOKEN_COST=0,
            G_TX_DATA_FLOOR_TOKEN_COST=0,
            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_AUTHORIZATION=0,
            R_AUTHORIZATION_EXISTING_AUTHORITY=0,
        )

    @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, 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, timestamp)

        def fn(*, data: BytesConvertible, floor: bool = False) -> int:
            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."""
        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."""
        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."""

        def fn(*, data: BytesConvertible) -> int:
            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, timestamp)
        calldata_gas_calculator = cls.calldata_gas_calculator(block_number, 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:
            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."""
        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."""
        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."""
        return 0

    @classmethod
    def supports_blobs(cls, block_number: int = 0, timestamp: int = 0) -> bool:
        """Blobs are not supported at Frontier."""
        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."""
        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."""
        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."""
        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."""
        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(
            f"Full blob transaction wrapper version is not supported in {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."""
        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."""
        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."""
        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."""
        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."""
        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."""
        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."""
        return False

    @classmethod
    def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0) -> bool:
        """At genesis, payloads do not have requests."""
        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."""
        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."""
        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."""
        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, 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, 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."""
        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.
        """
        return 5_000_000_000_000_000_000

    @classmethod
    def tx_types(cls, block_number: int = 0, timestamp: int = 0) -> List[int]:
        """At Genesis, only legacy transactions are allowed."""
        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."""
        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."""
        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."""
        return None

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

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

    @classmethod
    def evm_code_types(cls, block_number: int = 0, timestamp: int = 0) -> List[EVMCodeType]:
        """At Genesis, only legacy EVM code is supported."""
        return [EVMCodeType.LEGACY]

    @classmethod
    def max_code_size(cls) -> 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)"""
        return 0x6000

    @classmethod
    def max_stack_height(cls) -> int:
        """At genesis, the maximum stack height is 1024."""
        return 1024

    @classmethod
    def max_initcode_size(cls) -> int:
        """At genesis, there is no upper bound for initcode size."""
        """However, the default is set to the limit of EIP-3860 (Shanghai)"""
        return 0xC000

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

    @classmethod
    def valid_opcodes(
        cls,
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        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[Tuple[Opcodes, EVMCodeType]]:
        """At Genesis, only `CREATE` opcode is supported."""
        return [
            (Opcodes.CREATE, EVMCodeType.LEGACY),
        ]

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

    @classmethod
    def pre_allocation(cls) -> Mapping:
        """
        Return whether the fork expects pre-allocation of accounts.

        Frontier does not require pre-allocated accounts
        """
        return {}

    @classmethod
    def pre_allocation_blockchain(cls) -> Mapping:
        """
        Return whether the fork expects pre-allocation of accounts.

        Frontier does not require pre-allocated accounts
        """
        return {}

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 src/ethereum_test_forks/forks/forks.py
35
36
37
38
39
40
@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."""
    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 src/ethereum_test_forks/forks/forks.py
42
43
44
45
46
47
@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 src/ethereum_test_forks/forks/forks.py
49
50
51
52
@classmethod
def header_base_fee_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """At genesis, header must not contain base fee."""
    return False

header_prev_randao_required(block_number=0, timestamp=0) classmethod

At genesis, header must not contain Prev Randao value.

Source code in src/ethereum_test_forks/forks/forks.py
54
55
56
57
@classmethod
def header_prev_randao_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """At genesis, header must not contain Prev Randao value."""
    return False

header_zero_difficulty_required(block_number=0, timestamp=0) classmethod

At genesis, header must not have difficulty zero.

Source code in src/ethereum_test_forks/forks/forks.py
59
60
61
62
@classmethod
def header_zero_difficulty_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """At genesis, header must not have difficulty zero."""
    return False

header_withdrawals_required(block_number=0, timestamp=0) classmethod

At genesis, header must not contain withdrawals.

Source code in src/ethereum_test_forks/forks/forks.py
64
65
66
67
@classmethod
def header_withdrawals_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """At genesis, header must not contain withdrawals."""
    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 src/ethereum_test_forks/forks/forks.py
69
70
71
72
@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."""
    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 src/ethereum_test_forks/forks/forks.py
74
75
76
77
@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."""
    return False

gas_costs(block_number=0, timestamp=0) classmethod

Return dataclass with the defined gas costs constants for genesis.

Source code in src/ethereum_test_forks/forks/forks.py
 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
@classmethod
def gas_costs(cls, block_number: int = 0, timestamp: int = 0) -> GasCosts:
    """Return dataclass with the defined gas costs constants for genesis."""
    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_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_TX_DATA_STANDARD_TOKEN_COST=0,
        G_TX_DATA_FLOOR_TOKEN_COST=0,
        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_AUTHORIZATION=0,
        R_AUTHORIZATION_EXISTING_AUTHORITY=0,
    )

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 src/ethereum_test_forks/forks/forks.py
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
@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, 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 src/ethereum_test_forks/forks/forks.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
@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, timestamp)

    def fn(*, data: BytesConvertible, floor: bool = False) -> int:
        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 src/ethereum_test_forks/forks/forks.py
166
167
168
169
170
171
@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 src/ethereum_test_forks/forks/forks.py
173
174
175
176
177
178
179
180
181
@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 src/ethereum_test_forks/forks/forks.py
183
184
185
186
187
188
@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."""
    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 src/ethereum_test_forks/forks/forks.py
190
191
192
193
194
195
@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."""
    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 src/ethereum_test_forks/forks/forks.py
197
198
199
200
201
202
203
204
205
206
@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."""

    def fn(*, data: BytesConvertible) -> int:
        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 src/ethereum_test_forks/forks/forks.py
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
@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, timestamp)
    calldata_gas_calculator = cls.calldata_gas_calculator(block_number, 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:
        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 src/ethereum_test_forks/forks/forks.py
240
241
242
243
244
245
@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 src/ethereum_test_forks/forks/forks.py
247
248
249
250
251
252
@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 src/ethereum_test_forks/forks/forks.py
254
255
256
257
@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."""
    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 src/ethereum_test_forks/forks/forks.py
259
260
261
262
263
264
@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."""
    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 src/ethereum_test_forks/forks/forks.py
266
267
268
269
@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."""
    return 0

supports_blobs(block_number=0, timestamp=0) classmethod

Blobs are not supported at Frontier.

Source code in src/ethereum_test_forks/forks/forks.py
271
272
273
274
@classmethod
def supports_blobs(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Blobs are not supported at Frontier."""
    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 src/ethereum_test_forks/forks/forks.py
276
277
278
279
@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."""
    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 src/ethereum_test_forks/forks/forks.py
281
282
283
284
@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."""
    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 src/ethereum_test_forks/forks/forks.py
286
287
288
289
@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."""
    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 src/ethereum_test_forks/forks/forks.py
291
292
293
294
@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."""
    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 src/ethereum_test_forks/forks/forks.py
296
297
298
299
300
301
@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(
        f"Full blob transaction wrapper version is not supported in {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 src/ethereum_test_forks/forks/forks.py
303
304
305
306
@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."""
    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 src/ethereum_test_forks/forks/forks.py
308
309
310
311
@classmethod
def blob_schedule(cls, block_number: int = 0, timestamp: int = 0) -> BlobSchedule | None:
    """At genesis, no blob schedule is used."""
    return None

header_requests_required(block_number=0, timestamp=0) classmethod

At genesis, header must not contain beacon chain requests.

Source code in src/ethereum_test_forks/forks/forks.py
313
314
315
316
@classmethod
def header_requests_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """At genesis, header must not contain beacon chain requests."""
    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 src/ethereum_test_forks/forks/forks.py
318
319
320
321
322
323
@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."""
    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 src/ethereum_test_forks/forks/forks.py
325
326
327
328
@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."""
    return False

engine_new_payload_blob_hashes(block_number=0, timestamp=0) classmethod

At genesis, payloads do not have blob hashes.

Source code in src/ethereum_test_forks/forks/forks.py
330
331
332
333
@classmethod
def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """At genesis, payloads do not have blob hashes."""
    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 src/ethereum_test_forks/forks/forks.py
335
336
337
338
@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."""
    return False

engine_new_payload_requests(block_number=0, timestamp=0) classmethod

At genesis, payloads do not have requests.

Source code in src/ethereum_test_forks/forks/forks.py
340
341
342
343
@classmethod
def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """At genesis, payloads do not have requests."""
    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 src/ethereum_test_forks/forks/forks.py
345
346
347
348
349
350
351
352
@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."""
    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 src/ethereum_test_forks/forks/forks.py
354
355
356
357
358
359
@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."""
    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 src/ethereum_test_forks/forks/forks.py
361
362
363
364
365
366
@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."""
    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 src/ethereum_test_forks/forks/forks.py
368
369
370
371
372
373
@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, timestamp)

engine_get_payload_version(block_number=0, timestamp=0) classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
375
376
377
378
379
380
@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, timestamp)

engine_get_blobs_version(block_number=0, timestamp=0) classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
382
383
384
385
@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."""
    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 src/ethereum_test_forks/forks/forks.py
387
388
389
390
391
392
393
@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.
    """
    return 5_000_000_000_000_000_000

tx_types(block_number=0, timestamp=0) classmethod

At Genesis, only legacy transactions are allowed.

Source code in src/ethereum_test_forks/forks/forks.py
395
396
397
398
@classmethod
def tx_types(cls, block_number: int = 0, timestamp: int = 0) -> List[int]:
    """At Genesis, only legacy transactions are allowed."""
    return [0]

contract_creating_tx_types(block_number=0, timestamp=0) classmethod

At Genesis, only legacy transactions are allowed.

Source code in src/ethereum_test_forks/forks/forks.py
400
401
402
403
@classmethod
def contract_creating_tx_types(cls, block_number: int = 0, timestamp: int = 0) -> List[int]:
    """At Genesis, only legacy transactions are allowed."""
    return [0]

transaction_gas_limit_cap(block_number=0, timestamp=0) classmethod

At Genesis, no transaction gas limit cap is imposed.

Source code in src/ethereum_test_forks/forks/forks.py
405
406
407
408
@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."""
    return None

block_rlp_size_limit(block_number=0, timestamp=0) classmethod

At Genesis, no RLP block size limit is imposed.

Source code in src/ethereum_test_forks/forks/forks.py
410
411
412
413
@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."""
    return None

precompiles(block_number=0, timestamp=0) classmethod

At Genesis, no pre-compiles are present.

Source code in src/ethereum_test_forks/forks/forks.py
415
416
417
418
@classmethod
def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """At Genesis, no pre-compiles are present."""
    return []

system_contracts(block_number=0, timestamp=0) classmethod

At Genesis, no system-contracts are present.

Source code in src/ethereum_test_forks/forks/forks.py
420
421
422
423
@classmethod
def system_contracts(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """At Genesis, no system-contracts are present."""
    return []

evm_code_types(block_number=0, timestamp=0) classmethod

At Genesis, only legacy EVM code is supported.

Source code in src/ethereum_test_forks/forks/forks.py
425
426
427
428
@classmethod
def evm_code_types(cls, block_number: int = 0, timestamp: int = 0) -> List[EVMCodeType]:
    """At Genesis, only legacy EVM code is supported."""
    return [EVMCodeType.LEGACY]

max_code_size() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
430
431
432
433
434
@classmethod
def max_code_size(cls) -> 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)"""
    return 0x6000

max_stack_height() classmethod

At genesis, the maximum stack height is 1024.

Source code in src/ethereum_test_forks/forks/forks.py
436
437
438
439
@classmethod
def max_stack_height(cls) -> int:
    """At genesis, the maximum stack height is 1024."""
    return 1024

max_initcode_size() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
441
442
443
444
445
@classmethod
def max_initcode_size(cls) -> int:
    """At genesis, there is no upper bound for initcode size."""
    """However, the default is set to the limit of EIP-3860 (Shanghai)"""
    return 0xC000

call_opcodes(block_number=0, timestamp=0) classmethod

Return list of call opcodes supported by the fork.

Source code in src/ethereum_test_forks/forks/forks.py
447
448
449
450
451
452
453
454
455
@classmethod
def call_opcodes(
    cls, block_number: int = 0, timestamp: int = 0
) -> List[Tuple[Opcodes, EVMCodeType]]:
    """Return list of call opcodes supported by the fork."""
    return [
        (Opcodes.CALL, EVMCodeType.LEGACY),
        (Opcodes.CALLCODE, EVMCodeType.LEGACY),
    ]

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
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
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    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 src/ethereum_test_forks/forks/forks.py
594
595
596
597
598
599
600
601
@classmethod
def create_opcodes(
    cls, block_number: int = 0, timestamp: int = 0
) -> List[Tuple[Opcodes, EVMCodeType]]:
    """At Genesis, only `CREATE` opcode is supported."""
    return [
        (Opcodes.CREATE, EVMCodeType.LEGACY),
    ]

max_request_type(block_number=0, timestamp=0) classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
603
604
605
606
@classmethod
def max_request_type(cls, block_number: int = 0, timestamp: int = 0) -> int:
    """At genesis, no request type is supported, signaled by -1."""
    return -1

pre_allocation() classmethod

Return whether the fork expects pre-allocation of accounts.

Frontier does not require pre-allocated accounts

Source code in src/ethereum_test_forks/forks/forks.py
608
609
610
611
612
613
614
615
@classmethod
def pre_allocation(cls) -> Mapping:
    """
    Return whether the fork expects pre-allocation of accounts.

    Frontier does not require pre-allocated accounts
    """
    return {}

pre_allocation_blockchain() classmethod

Return whether the fork expects pre-allocation of accounts.

Frontier does not require pre-allocated accounts

Source code in src/ethereum_test_forks/forks/forks.py
617
618
619
620
621
622
623
624
@classmethod
def pre_allocation_blockchain(cls) -> Mapping:
    """
    Return whether the fork expects pre-allocation of accounts.

    Frontier does not require pre-allocated accounts
    """
    return {}

GrayGlacier

Bases: ArrowGlacier

Gray Glacier fork.

Source code in src/ethereum_test_forks/forks/forks.py
1052
1053
1054
1055
class GrayGlacier(ArrowGlacier, solc_name="london", ignore=True):
    """Gray Glacier fork."""

    pass

Homestead

Bases: Frontier

Homestead fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
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 pre-compiles
        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, timestamp)

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

    @classmethod
    def valid_opcodes(
        cls,
    ) -> List[Opcodes]:
        """Return the list of Opcodes that are valid to work on this fork."""
        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, timestamp
        )
        gas_costs = cls.gas_costs(block_number, 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,
                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 pre-compiles are introduced.

Source code in src/ethereum_test_forks/forks/forks.py
630
631
632
633
634
635
636
637
638
639
640
641
@classmethod
def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """
    At Homestead, EC-recover, SHA256, RIPEMD160, and Identity pre-compiles
    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, timestamp)

call_opcodes(block_number=0, timestamp=0) classmethod

At Homestead, DELEGATECALL opcode was introduced.

Source code in src/ethereum_test_forks/forks/forks.py
643
644
645
646
647
648
649
650
@classmethod
def call_opcodes(
    cls, block_number: int = 0, timestamp: int = 0
) -> List[Tuple[Opcodes, EVMCodeType]]:
    """At Homestead, DELEGATECALL opcode was introduced."""
    return [(Opcodes.DELEGATECALL, EVMCodeType.LEGACY)] + super(Homestead, cls).call_opcodes(
        block_number, timestamp
    )

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
652
653
654
655
656
657
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return the list of Opcodes that are valid to work on this fork."""
    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 src/ethereum_test_forks/forks/forks.py
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
@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, timestamp
    )
    gas_costs = cls.gas_costs(block_number, 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,
            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 src/ethereum_test_forks/forks/forks.py
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
class Istanbul(ConstantinopleFix):
    """Istanbul fork."""

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

    @classmethod
    def valid_opcodes(
        cls,
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        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, timestamp),
            G_TX_DATA_NON_ZERO=16,  # https://eips.ethereum.org/EIPS/eip-2028
        )

precompiles(block_number=0, timestamp=0) classmethod

At Istanbul, pre-compile for blake2 compression is introduced.

Source code in src/ethereum_test_forks/forks/forks.py
807
808
809
810
811
812
@classmethod
def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """At Istanbul, pre-compile for blake2 compression is introduced."""
    return [
        Address(9, label="BLAKE2F"),
    ] + super(Istanbul, cls).precompiles(block_number, timestamp)

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
814
815
816
817
818
819
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    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 src/ethereum_test_forks/forks/forks.py
821
822
823
824
825
826
827
828
829
830
@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, timestamp),
        G_TX_DATA_NON_ZERO=16,  # https://eips.ethereum.org/EIPS/eip-2028
    )

London

Bases: Berlin

London fork.

Source code in src/ethereum_test_forks/forks/forks.py
 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
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."""
        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, 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, timestamp)

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

    @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."""
        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."""
        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, timestamp
        )
        elasticity_multiplier = cls.base_fee_elasticity_multiplier(block_number, 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, timestamp
        )
        elasticity_multiplier = cls.base_fee_elasticity_multiplier(block_number, timestamp)
        base_fee_per_gas_calculator = cls.base_fee_per_gas_calculator(block_number, 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 src/ethereum_test_forks/forks/forks.py
889
890
891
892
@classmethod
def header_base_fee_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Header must contain the Base Fee starting from London."""
    return True

tx_types(block_number=0, timestamp=0) classmethod

At London, dynamic fee transactions are introduced.

Source code in src/ethereum_test_forks/forks/forks.py
894
895
896
897
@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, timestamp)

contract_creating_tx_types(block_number=0, timestamp=0) classmethod

At London, dynamic fee transactions are introduced.

Source code in src/ethereum_test_forks/forks/forks.py
899
900
901
902
@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, timestamp)

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
904
905
906
907
908
909
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    return [Opcodes.BASEFEE] + super(London, cls).valid_opcodes()

base_fee_max_change_denominator(block_number=0, timestamp=0) classmethod

Return the base fee max change denominator at London.

Source code in src/ethereum_test_forks/forks/forks.py
911
912
913
914
@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."""
    return 8

base_fee_elasticity_multiplier(block_number=0, timestamp=0) classmethod

Return the base fee elasticity multiplier at London.

Source code in src/ethereum_test_forks/forks/forks.py
916
917
918
919
@classmethod
def base_fee_elasticity_multiplier(cls, block_number: int = 0, timestamp: int = 0) -> int:
    """Return the base fee elasticity multiplier at London."""
    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 src/ethereum_test_forks/forks/forks.py
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
@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, timestamp
    )
    elasticity_multiplier = cls.base_fee_elasticity_multiplier(block_number, 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 src/ethereum_test_forks/forks/forks.py
 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
@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, timestamp
    )
    elasticity_multiplier = cls.base_fee_elasticity_multiplier(block_number, timestamp)
    base_fee_per_gas_calculator = cls.base_fee_per_gas_calculator(block_number, 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 src/ethereum_test_forks/forks/forks.py
834
835
836
837
class MuirGlacier(Istanbul, solc_name="istanbul", ignore=True):
    """Muir Glacier fork."""

    pass

Osaka

Bases: Prague

Osaka fork.

Source code in src/ethereum_test_forks/forks/forks.py
1598
1599
1600
1601
1602
1603
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
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
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."""
        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."""
        return 2

    @classmethod
    def full_blob_tx_wrapper_version(cls, block_number=0, timestamp=0) -> int | None:
        """At Osaka, the full blob transaction wrapper version is defined."""
        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)."""
        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."""
        max_block_size = 10_485_760
        safety_margin = 2_097_152
        return max_block_size - safety_margin

    @classmethod
    def is_deployed(cls) -> bool:
        """
        Flag that the fork has not been deployed to mainnet; it is under active
        development.
        """
        return False

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

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

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

    @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, timestamp)
        blob_gas_per_blob = cls.blob_gas_per_blob(block_number, 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, 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."""
        return 6

    @classmethod
    def blob_reserve_price_active(cls, block_number: int = 0, timestamp: int = 0) -> bool:
        """Blob reserve price is supported in Osaka."""
        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."""
        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 src/ethereum_test_forks/forks/forks.py
1607
1608
1609
1610
1611
1612
@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."""
    return 5

engine_get_blobs_version(block_number=0, timestamp=0) classmethod

At Osaka, the engine get blobs version is 2.

Source code in src/ethereum_test_forks/forks/forks.py
1614
1615
1616
1617
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1619
1620
1621
1622
@classmethod
def full_blob_tx_wrapper_version(cls, block_number=0, timestamp=0) -> int | None:
    """At Osaka, the full blob transaction wrapper version is defined."""
    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 src/ethereum_test_forks/forks/forks.py
1624
1625
1626
1627
@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)."""
    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 src/ethereum_test_forks/forks/forks.py
1629
1630
1631
1632
1633
1634
@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."""
    max_block_size = 10_485_760
    safety_margin = 2_097_152
    return max_block_size - safety_margin

is_deployed() classmethod

Flag that the fork has not been deployed to mainnet; it is under active development.

Source code in src/ethereum_test_forks/forks/forks.py
1636
1637
1638
1639
1640
1641
1642
@classmethod
def is_deployed(cls) -> bool:
    """
    Flag that the fork has not been deployed to mainnet; it is under active
    development.
    """
    return False

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
1644
1645
1646
1647
1648
1649
1650
1651
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    return [
        Opcodes.CLZ,
    ] + super(Prague, cls).valid_opcodes()

precompiles(block_number=0, timestamp=0) classmethod

At Osaka, pre-compile for p256verify operation is added.

P256VERIFY = 0x100

Source code in src/ethereum_test_forks/forks/forks.py
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
@classmethod
def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """
    At Osaka, pre-compile for p256verify operation is added.

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

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 src/ethereum_test_forks/forks/forks.py
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
@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, timestamp)
    blob_gas_per_blob = cls.blob_gas_per_blob(block_number, 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, 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 src/ethereum_test_forks/forks/forks.py
1713
1714
1715
1716
@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."""
    return 6

blob_reserve_price_active(block_number=0, timestamp=0) classmethod

Blob reserve price is supported in Osaka.

Source code in src/ethereum_test_forks/forks/forks.py
1718
1719
1720
1721
@classmethod
def blob_reserve_price_active(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Blob reserve price is supported in Osaka."""
    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 src/ethereum_test_forks/forks/forks.py
1723
1724
1725
1726
@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."""
    return 2**13  # EIP-7918 new parameter

Paris

Bases: London

Paris (Merge) fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
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."""
        return True

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

    @classmethod
    def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
        """Paris updates the reward to 0."""
        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."""
        return 1

header_prev_randao_required(block_number=0, timestamp=0) classmethod

Prev Randao is required starting from Paris.

Source code in src/ethereum_test_forks/forks/forks.py
1064
1065
1066
1067
@classmethod
def header_prev_randao_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Prev Randao is required starting from Paris."""
    return True

header_zero_difficulty_required(block_number=0, timestamp=0) classmethod

Zero difficulty is required starting from Paris.

Source code in src/ethereum_test_forks/forks/forks.py
1069
1070
1071
1072
@classmethod
def header_zero_difficulty_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Zero difficulty is required starting from Paris."""
    return True

get_reward(block_number=0, timestamp=0) classmethod

Paris updates the reward to 0.

Source code in src/ethereum_test_forks/forks/forks.py
1074
1075
1076
1077
@classmethod
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
    """Paris updates the reward to 0."""
    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 src/ethereum_test_forks/forks/forks.py
1079
1080
1081
1082
1083
1084
@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."""
    return 1

Prague

Bases: Cancun

Prague fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
1458
1459
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
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
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
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, pre-compile 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, 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, 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, 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,
        )

    @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, 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."""
        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, 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 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, timestamp)
        gas_costs = cls.gas_costs(block_number, 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, timestamp
        )
        gas_costs = cls.gas_costs(block_number, timestamp)
        transaction_data_floor_cost_calculator = cls.transaction_data_floor_cost_calculator(
            block_number, 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."""
        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."""
        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."""
        return 9

    @classmethod
    def pre_allocation_blockchain(cls) -> 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.
        """
        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.
        """
        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."""
        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."""
        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."""
        return 3

precompiles(block_number=0, timestamp=0) classmethod

At Prague, pre-compile 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 src/ethereum_test_forks/forks/forks.py
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
@classmethod
def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]:
    """
    At Prague, pre-compile 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, timestamp)

tx_types(block_number=0, timestamp=0) classmethod

At Prague, set-code type transactions are introduced.

Source code in src/ethereum_test_forks/forks/forks.py
1368
1369
1370
1371
@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, 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 src/ethereum_test_forks/forks/forks.py
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
@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, 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,
    )

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 src/ethereum_test_forks/forks/forks.py
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
@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, 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 src/ethereum_test_forks/forks/forks.py
1409
1410
1411
1412
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
@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, 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 src/ethereum_test_forks/forks/forks.py
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
@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, timestamp)
    gas_costs = cls.gas_costs(block_number, 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 src/ethereum_test_forks/forks/forks.py
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
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
@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, timestamp
    )
    gas_costs = cls.gas_costs(block_number, timestamp)
    transaction_data_floor_cost_calculator = cls.transaction_data_floor_cost_calculator(
        block_number, 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 src/ethereum_test_forks/forks/forks.py
1493
1494
1495
1496
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1498
1499
1500
1501
@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."""
    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 src/ethereum_test_forks/forks/forks.py
1503
1504
1505
1506
@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."""
    return 9

pre_allocation_blockchain() 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 src/ethereum_test_forks/forks/forks.py
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
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
@classmethod
def pre_allocation_blockchain(cls) -> 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.
    """
    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 src/ethereum_test_forks/forks/forks.py
1570
1571
1572
1573
1574
1575
1576
@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.
    """
    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 src/ethereum_test_forks/forks/forks.py
1578
1579
1580
1581
@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."""
    return True

engine_new_payload_version(block_number=0, timestamp=0) classmethod

From Prague, new payload calls must use version 4.

Source code in src/ethereum_test_forks/forks/forks.py
1583
1584
1585
1586
1587
1588
@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."""
    return 4

engine_forkchoice_updated_version(block_number=0, timestamp=0) classmethod

At Prague, version number of NewPayload and ForkchoiceUpdated diverge.

Source code in src/ethereum_test_forks/forks/forks.py
1590
1591
1592
1593
1594
1595
@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."""
    return 3

Shanghai

Bases: Paris

Shanghai fork.

Source code in src/ethereum_test_forks/forks/forks.py
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
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."""
        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."""
        return 2

    @classmethod
    def max_initcode_size(cls) -> int:
        """From Shanghai, the initcode size is now limited. See EIP-3860."""
        return 0xC000

    @classmethod
    def valid_opcodes(
        cls,
    ) -> List[Opcodes]:
        """Return list of Opcodes that are valid to work on this fork."""
        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 src/ethereum_test_forks/forks/forks.py
1090
1091
1092
1093
@classmethod
def header_withdrawals_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
    """Withdrawals are required starting from Shanghai."""
    return True

engine_new_payload_version(block_number=0, timestamp=0) classmethod

From Shanghai, new payload calls must use version 2.

Source code in src/ethereum_test_forks/forks/forks.py
1095
1096
1097
1098
1099
1100
@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."""
    return 2

max_initcode_size() classmethod

From Shanghai, the initcode size is now limited. See EIP-3860.

Source code in src/ethereum_test_forks/forks/forks.py
1102
1103
1104
1105
@classmethod
def max_initcode_size(cls) -> int:
    """From Shanghai, the initcode size is now limited. See EIP-3860."""
    return 0xC000

valid_opcodes() classmethod

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

Source code in src/ethereum_test_forks/forks/forks.py
1107
1108
1109
1110
1111
1112
@classmethod
def valid_opcodes(
    cls,
) -> List[Opcodes]:
    """Return list of Opcodes that are valid to work on this fork."""
    return [Opcodes.PUSH0] + super(Shanghai, cls).valid_opcodes()

BerlinToLondonAt5

Bases: Berlin

Berlin to London transition at Block 5.

Source code in src/ethereum_test_forks/forks/transition.py
 8
 9
10
11
12
@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 src/ethereum_test_forks/forks/transition.py
50
51
52
53
54
@transition_fork(to_fork=BPO2, at_timestamp=15_000)
class BPO1ToBPO2AtTime15k(BPO1):
    """BPO1 to BPO2 transition at Timestamp 15k."""

    pass

BPO2ToBPO3AtTime15k

Bases: BPO2

BPO2 to BPO3 transition at Timestamp 15k.

Source code in src/ethereum_test_forks/forks/transition.py
57
58
59
60
61
@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 src/ethereum_test_forks/forks/transition.py
64
65
66
67
68
@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 src/ethereum_test_forks/forks/transition.py
29
30
31
32
33
@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 src/ethereum_test_forks/forks/transition.py
43
44
45
46
47
@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 src/ethereum_test_forks/forks/transition.py
15
16
17
18
19
@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 src/ethereum_test_forks/forks/transition.py
36
37
38
39
40
@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 src/ethereum_test_forks/forks/transition.py
22
23
24
25
26
@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 src/ethereum_test_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
@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_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

    R_AUTHORIZATION_EXISTING_AUTHORITY: int

ForkRangeDescriptor

Bases: BaseModel

Fork descriptor parsed from string normally contained in ethereum/tests fillers.

Source code in src/ethereum_test_forks/helpers.py
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
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):
        """
        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 src/ethereum_test_forks/helpers.py
312
313
314
315
316
317
318
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 src/ethereum_test_forks/helpers.py
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
@model_validator(mode="wrap")
@classmethod
def validate_fork_range_descriptor(cls, v: Any, handler: ValidatorFunctionWrapHandler):
    """
    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 src/ethereum_test_forks/helpers.py
23
24
25
26
27
28
class InvalidForkError(Exception):
    """Invalid fork error raised when the fork specified is not found or incompatible."""

    def __init__(self, message):
        """Initialize the InvalidForkError exception."""
        super().__init__(message)

__init__(message)

Initialize the InvalidForkError exception.

Source code in src/ethereum_test_forks/helpers.py
26
27
28
def __init__(self, message):
    """Initialize the InvalidForkError exception."""
    super().__init__(message)

forks_from(fork, deployed_only=True)

Return specified fork and all forks after it.

Source code in src/ethereum_test_forks/helpers.py
255
256
257
258
259
260
261
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 src/ethereum_test_forks/helpers.py
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
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, solc_version)

Return None if BaseFork is passed, otherwise return the fork itself.

Source code in src/ethereum_test_forks/helpers.py
89
90
91
92
93
def get_closest_fork(fork: Type[BaseFork], solc_version: Version) -> 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 list of all the fork classes implemented by ethereum_test_forks that have been deployed to mainnet, chronologically ordered by deployment.

Source code in src/ethereum_test_forks/helpers.py
64
65
66
67
68
69
def get_deployed_forks() -> List[Type[BaseFork]]:
    """
    Return list of all the fork classes implemented by `ethereum_test_forks`
    that have been deployed to mainnet, chronologically ordered by deployment.
    """
    return [fork for fork in get_forks() if fork.is_deployed() and not fork.ignore()]

get_development_forks()

Return list of all the fork classes implemented by ethereum_test_forks that have been not yet deployed to mainnet and are currently under development. The list is ordered by their planned deployment date.

Source code in src/ethereum_test_forks/helpers.py
72
73
74
75
76
77
78
def get_development_forks() -> List[Type[BaseFork]]:
    """
    Return list of all the fork classes implemented by `ethereum_test_forks`
    that have been not yet deployed to mainnet and are currently 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 src/ethereum_test_forks/helpers.py
297
298
299
300
301
302
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 list of all the fork classes implemented by ethereum_test_forks ordered chronologically by deployment.

Source code in src/ethereum_test_forks/helpers.py
56
57
58
59
60
61
def get_forks() -> List[Type[BaseFork]]:
    """
    Return list of all the fork classes implemented by
    `ethereum_test_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 src/ethereum_test_forks/helpers.py
146
147
148
149
150
151
152
153
154
155
156
157
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 src/ethereum_test_forks/helpers.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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 src/ethereum_test_forks/helpers.py
115
116
117
118
119
120
121
122
123
124
125
126
127
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 src/ethereum_test_forks/helpers.py
160
161
162
163
164
165
166
167
168
169
170
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 src/ethereum_test_forks/helpers.py
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
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 src/ethereum_test_forks/helpers.py
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
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 src/ethereum_test_forks/helpers.py
101
102
103
104
105
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 src/ethereum_test_forks/helpers.py
108
109
110
111
112
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 src/ethereum_test_forks/helpers.py
96
97
98
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 src/ethereum_test_forks/helpers.py
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
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 src/ethereum_test_forks/helpers.py
219
220
221
222
223
224
225
226
227
228
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