Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading