Skip to content

Commit

Permalink
src/ethereum_test_tools: State test filling correctly.
Browse files Browse the repository at this point in the history
  • Loading branch information
spencer-tb committed Sep 26, 2023
1 parent f536d81 commit 0dfcda5
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 94 deletions.
1 change: 1 addition & 0 deletions src/ethereum_test_tools/common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2791,6 +2791,7 @@ class Fixture(BaseFixture):
),
)
seal_engine: str = field(
default="NoProof",
json_encoder=JSONEncoder.Field(
name="sealEngine",
),
Expand Down
40 changes: 3 additions & 37 deletions src/ethereum_test_tools/filling/fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from ethereum_test_forks import Fork
from evm_transition_tool import TransitionTool

from ..common import Fixture, HiveFixture, alloc_to_accounts
from ..common import Fixture, HiveFixture
from ..reference_spec.reference_spec import ReferenceSpec
from ..spec import BaseTest

Expand All @@ -15,56 +15,22 @@ def fill_test(
t8n: TransitionTool,
test_spec: BaseTest,
fork: Fork,
engine: str,
spec: ReferenceSpec | None,
eips: Optional[List[int]] = None,
) -> Optional[Union[Fixture, HiveFixture]]:
"""
Fills fixtures for the specified fork.
"""
t8n.reset_traces()

pre, genesis_rlp, genesis = test_spec.make_genesis(t8n, fork)

(blocks, payloads, head, alloc, fcu_version) = test_spec.make_blocks(
t8n,
genesis,
pre,
fork,
eips=eips,
)

network_info = (
"+".join([fork.name()] + [str(eip) for eip in eips]) if eips is not None else fork.name()
)

fixture: Union[Fixture, HiveFixture]
if test_spec.base_test_config.enable_hive:
if fork.engine_new_payload_version() is not None:
fixture = HiveFixture(
payloads=payloads,
fcu_version=fcu_version,
genesis=genesis,
fork=network_info,
pre_state=pre,
post_state=alloc_to_accounts(alloc),
name=test_spec.tag,
)
fixture = test_spec.make_hive_fixture(t8n, fork, eips)
else: # pre Merge tests are not supported in Hive
# TODO: remove this logic. if hive enabled set --from to Merge
return None
else:
fixture = Fixture(
blocks=blocks,
genesis=genesis,
genesis_rlp=genesis_rlp,
head=head,
fork=network_info,
pre_state=pre,
post_state=alloc_to_accounts(alloc),
seal_engine=engine,
name=test_spec.tag,
)
fixture = test_spec.make_fixture(t8n, fork, eips)
fixture.fill_info(t8n, spec)

return fixture
8 changes: 0 additions & 8 deletions src/ethereum_test_tools/spec/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@
from ..common import (
Account,
Address,
Alloc,
Environment,
Fixture,
FixtureHeader,
HiveFixture,
Transaction,
withdrawals_root,
Expand Down Expand Up @@ -110,10 +108,7 @@ class BaseTest:
def make_fixture(
self,
t8n: TransitionTool,
genesis: FixtureHeader,
pre: Alloc,
fork: Fork,
chain_id: int = 1,
eips: Optional[List[int]] = None,
) -> Fixture:
"""
Expand All @@ -125,10 +120,7 @@ def make_fixture(
def make_hive_fixture(
self,
t8n: TransitionTool,
genesis: FixtureHeader,
pre: Alloc,
fork: Fork,
chain_id: int = 1,
eips: Optional[List[int]] = None,
) -> HiveFixture:
"""
Expand Down
147 changes: 110 additions & 37 deletions src/ethereum_test_tools/spec/state_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
from copy import copy
from dataclasses import dataclass
from typing import Any, Callable, Dict, Generator, List, Mapping, Optional, Tuple, Type
from typing import Callable, Generator, List, Mapping, Optional, Tuple, Type

from ethereum_test_forks import Fork
from evm_transition_tool import TransitionTool
Expand All @@ -15,14 +15,17 @@
Bytes,
EmptyTrieRoot,
Environment,
Fixture,
FixtureBlock,
FixtureEngineNewPayload,
FixtureHeader,
Hash,
HeaderNonce,
HiveFixture,
Number,
Transaction,
ZeroPaddedHexNumber,
alloc_to_accounts,
to_json,
)
from ..common.constants import EmptyOmmersRoot, EngineAPIError
Expand Down Expand Up @@ -121,25 +124,25 @@ def make_genesis(

return Alloc(new_alloc), genesis_rlp, genesis

def make_blocks(
def make_fixture(
self,
t8n: TransitionTool,
genesis: FixtureHeader,
pre: Alloc,
fork: Fork,
eips: Optional[List[int]] = None,
) -> Tuple[
Optional[List[FixtureBlock]],
Optional[List[Optional[FixtureEngineNewPayload]]],
Hash,
Dict[str, Any],
Optional[int],
]:
) -> Fixture:
"""
Create a block from the state test definition.
Performs checks against the expected behavior of the test.
Raises exception on invalid test behavior.
"""
pre, genesis_rlp, genesis = self.make_genesis(t8n, fork)

network_info = (
"+".join([fork.name()] + [str(eip) for eip in eips])
if eips is not None
else fork.name()
)

env = self.env.apply_new_parent(genesis)
env = env.set_fork_requirements(fork)

Expand Down Expand Up @@ -185,36 +188,106 @@ def make_blocks(
withdrawals=env.withdrawals,
)

fcu_version: int | None = None
fixture_payload: FixtureEngineNewPayload | None = None
fixture_block: FixtureBlock | None = None
if self.base_test_config.enable_hive:
fcu_version = fork.engine_forkchoice_updated_version(header.number, header.timestamp)
fixture_payload = FixtureEngineNewPayload.from_fixture_header(
fork=fork,
header=header,
transactions=txs,
withdrawals=env.withdrawals,
valid=True,
error_code=None,
)
else:
fixture_block = FixtureBlock(
rlp=block,
block_header=header,
txs=txs,
ommers=[],
withdrawals=env.withdrawals,
fixture = Fixture(
fork=network_info,
genesis=genesis,
genesis_rlp=genesis_rlp,
blocks=[
FixtureBlock(
rlp=block,
block_header=header,
txs=txs,
ommers=[],
withdrawals=env.withdrawals,
)
],
head=header.hash,
pre_state=pre,
post_state=alloc_to_accounts(alloc),
name=self.tag,
)
return fixture

def make_hive_fixture(
self,
t8n: TransitionTool,
fork: Fork,
eips: Optional[List[int]] = None,
) -> HiveFixture:
"""
Create a block from the state test definition.
Performs checks against the expected behavior of the test.
Raises exception on invalid test behavior.
"""
pre, _, genesis = self.make_genesis(t8n, fork)

network_info = (
"+".join([fork.name()] + [str(eip) for eip in eips])
if eips is not None
else fork.name()
)

env = self.env.apply_new_parent(genesis)
env = env.set_fork_requirements(fork)

txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []

alloc, result = t8n.evaluate(
alloc=to_json(pre),
txs=to_json(txs),
env=to_json(env),
fork_name=fork.fork(block_number=Number(env.number), timestamp=Number(env.timestamp)),
chain_id=self.chain_id,
reward=fork.get_reward(Number(env.number), Number(env.timestamp)),
eips=eips,
debug_output_path=self.get_next_transition_tool_output_path(),
)

rejected_txs = verify_transactions(txs, result)
if len(rejected_txs) > 0:
raise Exception(
"one or more transactions in `StateTest` are "
+ "intrinsically invalid, which are not allowed. "
+ "Use `BlockchainTest` to verify rejection of blocks "
+ "that include invalid transactions."
)

return (
[fixture_block] if fixture_block is not None else None,
[fixture_payload] if fixture_payload is not None else None,
header.hash,
alloc,
fcu_version,
try:
verify_post_alloc(self.post, alloc)
verify_result(result, env)
except Exception as e:
print_traces(traces=t8n.get_traces())
raise e

env.extra_data = b"\x00"
header = FixtureHeader.collect(
fork=fork,
transition_tool_result=result,
environment=env,
)

fixture_payload = FixtureEngineNewPayload.from_fixture_header(
fork=fork,
header=header,
transactions=txs,
withdrawals=env.withdrawals,
valid=True,
error_code=None,
)
fcu_version = fork.engine_forkchoice_updated_version(header.number, header.timestamp)

hive_fixture = HiveFixture(
fork=network_info,
genesis=genesis,
payloads=[fixture_payload],
fcu_version=fcu_version,
pre_state=pre,
post_state=alloc_to_accounts(alloc),
name=self.tag,
)

return hive_fixture


StateTestSpec = Callable[[str], Generator[StateTest, None, None]]
StateTestFiller = Type[StateTest]
14 changes: 2 additions & 12 deletions src/pytest_plugins/test_filler/test_filler.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,14 +300,6 @@ def fixture_collector(request):
fixture_collector.dump_fixtures()


@pytest.fixture(autouse=True, scope="session")
def engine():
"""
Returns the sealEngine used in the generated test fixtures.
"""
return "NoProof"


@pytest.fixture(autouse=True, scope="session")
def filler_path(request):
"""
Expand Down Expand Up @@ -363,7 +355,7 @@ def __init__(self, *args, **kwargs):

@pytest.fixture(scope="function")
def state_test(
request, t8n, fork, engine, reference_spec, eips, fixture_collector, base_test_config
request, t8n, fork, reference_spec, eips, fixture_collector, base_test_config
) -> StateTestFiller:
"""
Fixture used to instantiate an auto-fillable StateTest object from within
Expand Down Expand Up @@ -391,7 +383,6 @@ def __init__(self, *args, **kwargs):
t8n,
self,
fork,
engine,
reference_spec,
eips=eips,
),
Expand All @@ -402,7 +393,7 @@ def __init__(self, *args, **kwargs):

@pytest.fixture(scope="function")
def blockchain_test(
request, t8n, fork, engine, reference_spec, eips, fixture_collector, base_test_config
request, t8n, fork, reference_spec, eips, fixture_collector, base_test_config
) -> BlockchainTestFiller:
"""
Fixture used to define an auto-fillable BlockchainTest analogous to the
Expand All @@ -424,7 +415,6 @@ def __init__(self, *args, **kwargs):
t8n,
self,
fork,
engine,
reference_spec,
eips=eips,
),
Expand Down

0 comments on commit 0dfcda5

Please sign in to comment.