Skip to content

Commit

Permalink
Merge pull request #1075 from ethereum/interstate
Browse files Browse the repository at this point in the history
feat(specs): verify intermidiate block state in blockchain test
  • Loading branch information
winsvega authored Jan 20, 2025
2 parents 54f0b43 + 7053c31 commit bdce2dc
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 4 deletions.
26 changes: 22 additions & 4 deletions src/ethereum_test_specs/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ class Block(Header):
"""
Custom list of requests to embed in this block.
"""
expected_post_state: Alloc | None = None
"""
Post state for verification after block execution in BlockchainTest
"""

def set_environment(self, env: Environment) -> Environment:
"""
Expand Down Expand Up @@ -491,10 +495,13 @@ def network_info(self, fork: Fork, eips: Optional[List[int]] = None):
else fork.blockchain_test_network_name()
)

def verify_post_state(self, t8n, alloc: Alloc):
def verify_post_state(self, t8n, t8n_state: Alloc, expected_state: Alloc | None = None):
"""Verify post alloc after all block/s or payload/s are generated."""
try:
self.post.verify_post_alloc(alloc)
if expected_state:
expected_state.verify_post_alloc(t8n_state)
else:
self.post.verify_post_alloc(t8n_state)
except Exception as e:
print_traces(t8n.get_traces())
raise e
Expand Down Expand Up @@ -570,7 +577,12 @@ def make_fixture(
),
)

self.verify_post_state(t8n, alloc)
if block.expected_post_state:
self.verify_post_state(
t8n, t8n_state=alloc, expected_state=block.expected_post_state
)

self.verify_post_state(t8n, t8n_state=alloc)
return Fixture(
fork=self.network_info(fork, eips),
genesis=genesis.header,
Expand Down Expand Up @@ -622,13 +634,19 @@ def make_hive_fixture(
alloc = new_alloc
env = apply_new_parent(env, header)
head_hash = header.block_hash

if block.expected_post_state:
self.verify_post_state(
t8n, t8n_state=alloc, expected_state=block.expected_post_state
)

fcu_version = fork.engine_forkchoice_updated_version(header.number, header.timestamp)
assert (
fcu_version is not None
), "A hive fixture was requested but no forkchoice update is defined. The framework should"
" never try to execute this test case."

self.verify_post_state(t8n, alloc)
self.verify_post_state(t8n, t8n_state=alloc)

sync_payload: Optional[FixtureEngineNewPayload] = None
if self.verify_sync:
Expand Down
98 changes: 98 additions & 0 deletions src/ethereum_test_specs/tests/test_expect.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
from ethereum_test_exceptions import TransactionException
from ethereum_test_fixtures import BlockchainFixture, FixtureFormat, StateFixture
from ethereum_test_forks import Fork, get_deployed_forks
from ethereum_test_tools import Block
from ethereum_test_types import Alloc, Environment, Storage, Transaction, TransactionReceipt

from ..blockchain import BlockchainEngineFixture, BlockchainTest
from ..helpers import (
TransactionExceptionMismatchError,
TransactionReceiptMismatchError,
Expand Down Expand Up @@ -349,3 +351,99 @@ def test_transaction_expectation(
else:
with pytest.raises(exception_type) as _:
state_test.generate(request=None, t8n=t8n, fork=fork, fixture_format=fixture_format)


@pytest.mark.parametrize(
"intermediate_state,expected_exception",
[
pytest.param(
{
TestAddress: Account(nonce=1),
Address(0x01): Account(balance=1),
},
None,
id="NoException",
),
pytest.param(
{
TestAddress: Account(nonce=2),
Address(0x01): Account(balance=1),
},
Account.NonceMismatchError,
id="NonceMismatchError",
),
pytest.param(
{
TestAddress: Account(nonce=1),
Address(0x01): Account(balance=2),
},
Account.BalanceMismatchError,
id="BalanceMismatchError",
),
],
)
@pytest.mark.parametrize(
"fixture_format",
[
BlockchainFixture,
BlockchainEngineFixture,
],
)
def test_block_intermediate_state(
pre, t8n, fork, fixture_format: FixtureFormat, intermediate_state, expected_exception
):
"""Validate the state when building blockchain."""
env = Environment()

to = Address(0x01)
tx = Transaction(gas_limit=100_000, to=to, value=1, nonce=0, secret_key=TestPrivateKey)
tx_2 = Transaction(gas_limit=100_000, to=to, value=1, nonce=1, secret_key=TestPrivateKey)

block_1 = Block(
txs=[tx],
expected_post_state={
TestAddress: Account(nonce=1),
to: Account(balance=1),
},
)

block_2 = Block(txs=[], expected_post_state=intermediate_state)

block_3 = Block(
txs=[tx_2],
expected_post_state={
TestAddress: Account(nonce=2),
to: Account(balance=2),
},
)

if expected_exception:
with pytest.raises(expected_exception) as _:
BlockchainTest(
genesis_environment=env,
fork=fork,
t8n=t8n,
pre=pre,
post=block_3.expected_post_state,
blocks=[block_1, block_2, block_3],
).generate(
request=None, # type: ignore
t8n=t8n,
fork=fork,
fixture_format=fixture_format,
)
return
else:
BlockchainTest(
genesis_environment=env,
fork=fork,
t8n=t8n,
pre=pre,
post=block_3.expected_post_state,
blocks=[block_1, block_2, block_3],
).generate(
request=None, # type: ignore
t8n=t8n,
fork=fork,
fixture_format=fixture_format,
)
1 change: 1 addition & 0 deletions tests/frontier/examples/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Test examples, patterns, templates to use in .py tests."""
50 changes: 50 additions & 0 deletions tests/frontier/examples/test_block_intermediate_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Test the SELFDESTRUCT opcode."""

import pytest

from ethereum_test_tools import (
Account,
Alloc,
Block,
BlockchainTestFiller,
Environment,
Transaction,
)


@pytest.mark.valid_from("Frontier")
@pytest.mark.valid_until("Homestead")
def test_block_intermidiate_state(blockchain_test: BlockchainTestFiller, pre: Alloc):
"""Verify intermidiate block states."""
env = Environment()
sender = pre.fund_eoa()

tx = Transaction(gas_limit=100_000, to=None, data=b"", sender=sender, protected=False)
tx_2 = Transaction(gas_limit=100_000, to=None, data=b"", sender=sender, protected=False)

block_1 = Block(
txs=[tx],
expected_post_state={
sender: Account(
nonce=1,
),
},
)

block_2 = Block(txs=[])

block_3 = Block(
txs=[tx_2],
expected_post_state={
sender: Account(
nonce=2,
),
},
)

blockchain_test(
genesis_environment=env,
pre=pre,
post=block_3.expected_post_state,
blocks=[block_1, block_2, block_3],
)
1 change: 1 addition & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ isort
isort's
ispkg
itemName
intermidiate
javascripts
jimporter
joinpath
Expand Down

0 comments on commit bdce2dc

Please sign in to comment.