Skip to content

Commit 0844e08

Browse files
committed
tools: state_test_only, genesis blockchain modifications
1 parent 5272ff4 commit 0844e08

File tree

5 files changed

+124
-4
lines changed

5 files changed

+124
-4
lines changed

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Test fixtures for use by clients are available for each release on the [Github r
1616
- ✨ Fork objects used to write tests can now be compared using the `>`, `>=`, `<`, `<=` operators, to check for a fork being newer than, newer than or equal, older than, older than or equal, respectively when compared against other fork ([#367](https://github.com/ethereum/execution-spec-tests/pull/367))
1717
- 💥 Removed `--enable-hive` parameter, now all test types are generated by default ([#358](https://github.com/ethereum/execution-spec-tests/pull/358))
1818
- 💥 `StateTest`, spec format used to write tests, is now limited to a single transaction per test ([#361](https://github.com/ethereum/execution-spec-tests/pull/361))
19+
-`StateTestOnly`, spec format is now available and its only difference with `StateTest` is that it does not produce a `BlockchainTest` ([#368](https://github.com/ethereum/execution-spec-tests/pull/368))
1920

2021
### 🔧 EVM Tools
2122

src/ethereum_test_tools/spec/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
from .base.base_test import BaseFixture, BaseTest, TestSpec, verify_post_alloc
77
from .blockchain.blockchain_test import BlockchainTest, BlockchainTestFiller, BlockchainTestSpec
88
from .fixture_collector import FixtureCollector, TestInfo
9-
from .state.state_test import StateTest, StateTestFiller, StateTestSpec
9+
from .state.state_test import StateTest, StateTestFiller, StateTestOnly, StateTestSpec
1010

11-
SPEC_TYPES: List[Type[BaseTest]] = [BlockchainTest, StateTest]
11+
SPEC_TYPES: List[Type[BaseTest]] = [BlockchainTest, StateTest, StateTestOnly]
1212

1313
__all__ = (
1414
"SPEC_TYPES",
@@ -20,6 +20,7 @@
2020
"FixtureCollector",
2121
"StateTest",
2222
"StateTestFiller",
23+
"StateTestOnly",
2324
"StateTestSpec",
2425
"TestInfo",
2526
"TestSpec",

src/ethereum_test_tools/spec/blockchain/types.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,14 +410,19 @@ def verify(self, baseline: Header):
410410
assert baseline_value is not Header.REMOVE_FIELD, "invalid baseline header"
411411
value = getattr(self, field_name)
412412
if baseline_value is Header.EMPTY_FIELD:
413-
assert value is None, f"invalid header field {header_field}"
413+
assert (
414+
value is None
415+
), f"invalid header field {field_name}, got {value}, want None"
414416
continue
415417
metadata = header_field.metadata
416418
field_metadata = metadata.get("source")
417419
# type check is performed on collect()
418420
if field_metadata.parse_type is not None: # type: ignore
419421
baseline_value = field_metadata.parse_type(baseline_value) # type: ignore
420-
assert value == baseline_value, f"invalid header field {header_field}"
422+
assert value == baseline_value, (
423+
f"invalid header field ({field_name}) value, "
424+
+ f"got {value}, want {baseline_value}"
425+
)
421426

422427
def build(
423428
self,

src/ethereum_test_tools/spec/state/state_test.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
from ...common.json import to_json
1414
from ..base.base_test import BaseFixture, BaseTest, verify_post_alloc
1515
from ..blockchain.blockchain_test import Block, BlockchainTest
16+
from ..blockchain.types import Header
1617
from ..debugging import print_traces
1718
from .types import Fixture, FixtureForkPost
1819

1920
BEACON_ROOTS_ADDRESS = Address(0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02)
21+
TARGET_BLOB_GAS_PER_BLOCK = 393216
2022

2123

2224
@dataclass(kw_only=True)
@@ -30,6 +32,8 @@ class StateTest(BaseTest):
3032
post: Mapping
3133
tx: Transaction
3234
engine_api_error_code: Optional[EngineAPIError] = None
35+
blockchain_test_header_verify: Optional[Header] = None
36+
blockchain_test_rlp_modifier: Optional[Header] = None
3337
tag: str = ""
3438
chain_id: int = 1
3539

@@ -58,12 +62,22 @@ def _generate_blockchain_genesis_environment(self) -> Environment:
5862
genesis_env = copy(self.env)
5963

6064
# Modify values to the proper values for the genesis block
65+
# TODO: All of this can be moved to a new method in `Fork`
6166
genesis_env.withdrawals = None
6267
genesis_env.beacon_root = None
6368
genesis_env.number = Number(genesis_env.number) - 1
6469
assert (
6570
genesis_env.number >= 0
6671
), "genesis block number cannot be negative, set state test env.number to 1"
72+
if genesis_env.excess_blob_gas:
73+
# The excess blob gas environment value means the value of the context (block header)
74+
# where the transaction is executed. In a blockchain test, we need to indirectly
75+
# set the excess blob gas by setting the excess blob gas of the genesis block
76+
# to the expected value plus the TARGET_BLOB_GAS_PER_BLOCK, which is the value
77+
# that will be subtracted from the excess blob gas when the first block is mined.
78+
genesis_env.excess_blob_gas = (
79+
Number(genesis_env.excess_blob_gas) + TARGET_BLOB_GAS_PER_BLOCK
80+
)
6781

6882
return genesis_env
6983

@@ -83,6 +97,9 @@ def _generate_blockchain_blocks(self) -> List[Block]:
8397
beacon_root=self.env.beacon_root,
8498
txs=[self.tx],
8599
ommers=[],
100+
exception=self.tx.error,
101+
header_verify=self.blockchain_test_header_verify,
102+
rlp_modifier=self.blockchain_test_rlp_modifier,
86103
)
87104
]
88105

@@ -186,5 +203,25 @@ def generate(
186203
raise Exception(f"Unknown fixture format: {self.fixture_format}")
187204

188205

206+
class StateTestOnly(StateTest):
207+
"""
208+
StateTest filler that only generates a state test fixture.
209+
"""
210+
211+
@classmethod
212+
def pytest_parameter_name(cls) -> str:
213+
"""
214+
Returns the parameter name used to identify this filler in a test.
215+
"""
216+
return "state_test_only"
217+
218+
@classmethod
219+
def fixture_formats(cls) -> List[FixtureFormats]:
220+
"""
221+
Returns a list of fixture formats that can be output to the test spec.
222+
"""
223+
return [FixtureFormats.STATE_TEST]
224+
225+
189226
StateTestSpec = Callable[[str], Generator[StateTest, None, None]]
190227
StateTestFiller = Type[StateTest]

src/ethereum_test_tools/spec/state/types.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,86 @@
1919
Environment,
2020
Hash,
2121
HexNumber,
22+
Number,
23+
NumberConvertible,
2224
Transaction,
2325
ZeroPaddedHexNumber,
2426
)
2527
from ..base.base_test import BaseFixture
2628

2729

30+
@dataclass(kw_only=True)
31+
class FixtureEnvironment:
32+
"""
33+
Type used to describe the environment of a state test.
34+
"""
35+
36+
coinbase: FixedSizeBytesConvertible = field(
37+
default="0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
38+
json_encoder=JSONEncoder.Field(
39+
name="currentCoinbase",
40+
cast_type=Address,
41+
),
42+
)
43+
gas_limit: NumberConvertible = field(
44+
default=100000000000000000,
45+
json_encoder=JSONEncoder.Field(
46+
name="currentGasLimit",
47+
cast_type=Number,
48+
),
49+
)
50+
number: NumberConvertible = field(
51+
default=1,
52+
json_encoder=JSONEncoder.Field(
53+
name="currentNumber",
54+
cast_type=Number,
55+
),
56+
)
57+
timestamp: NumberConvertible = field(
58+
default=1000,
59+
json_encoder=JSONEncoder.Field(
60+
name="currentTimestamp",
61+
cast_type=Number,
62+
),
63+
)
64+
prev_randao: Optional[NumberConvertible] = field(
65+
default=None,
66+
json_encoder=JSONEncoder.Field(
67+
name="currentRandom",
68+
cast_type=Number,
69+
),
70+
)
71+
difficulty: Optional[NumberConvertible] = field(
72+
default=None,
73+
json_encoder=JSONEncoder.Field(
74+
name="currentDifficulty",
75+
cast_type=Number,
76+
),
77+
)
78+
base_fee: Optional[NumberConvertible] = field(
79+
default=None,
80+
json_encoder=JSONEncoder.Field(
81+
name="currentBaseFee",
82+
cast_type=Number,
83+
),
84+
)
85+
excess_blob_gas: Optional[NumberConvertible] = field(
86+
default=None,
87+
json_encoder=JSONEncoder.Field(
88+
name="currentExcessBlobGas",
89+
cast_type=Number,
90+
),
91+
)
92+
93+
@classmethod
94+
def from_env(cls, env: Environment) -> "FixtureEnvironment":
95+
"""
96+
Returns a FixtureEnvironment from an Environment.
97+
"""
98+
kwargs = {field.name: getattr(env, field.name) for field in fields(cls)}
99+
return cls(**kwargs)
100+
101+
28102
@dataclass(kw_only=True)
29103
class FixtureTransaction:
30104
"""
@@ -195,6 +269,7 @@ def collect(
195269
state_root=state_root,
196270
logs_hash=logs_hash,
197271
tx_bytes=transaction.serialized_bytes(),
272+
expected_exception=transaction.error,
198273
indexes=indexes,
199274
)
200275

@@ -207,6 +282,7 @@ class Fixture(BaseFixture):
207282

208283
env: Environment = field(
209284
json_encoder=JSONEncoder.Field(
285+
cast_type=FixtureEnvironment.from_env,
210286
to_json=True,
211287
),
212288
)

0 commit comments

Comments
 (0)