Skip to content

Commit bdce2dc

Browse files
authored
Merge pull request #1075 from ethereum/interstate
feat(specs): verify intermidiate block state in blockchain test
2 parents 54f0b43 + 7053c31 commit bdce2dc

File tree

5 files changed

+172
-4
lines changed

5 files changed

+172
-4
lines changed

src/ethereum_test_specs/blockchain.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ class Block(Header):
224224
"""
225225
Custom list of requests to embed in this block.
226226
"""
227+
expected_post_state: Alloc | None = None
228+
"""
229+
Post state for verification after block execution in BlockchainTest
230+
"""
227231

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

494-
def verify_post_state(self, t8n, alloc: Alloc):
498+
def verify_post_state(self, t8n, t8n_state: Alloc, expected_state: Alloc | None = None):
495499
"""Verify post alloc after all block/s or payload/s are generated."""
496500
try:
497-
self.post.verify_post_alloc(alloc)
501+
if expected_state:
502+
expected_state.verify_post_alloc(t8n_state)
503+
else:
504+
self.post.verify_post_alloc(t8n_state)
498505
except Exception as e:
499506
print_traces(t8n.get_traces())
500507
raise e
@@ -570,7 +577,12 @@ def make_fixture(
570577
),
571578
)
572579

573-
self.verify_post_state(t8n, alloc)
580+
if block.expected_post_state:
581+
self.verify_post_state(
582+
t8n, t8n_state=alloc, expected_state=block.expected_post_state
583+
)
584+
585+
self.verify_post_state(t8n, t8n_state=alloc)
574586
return Fixture(
575587
fork=self.network_info(fork, eips),
576588
genesis=genesis.header,
@@ -622,13 +634,19 @@ def make_hive_fixture(
622634
alloc = new_alloc
623635
env = apply_new_parent(env, header)
624636
head_hash = header.block_hash
637+
638+
if block.expected_post_state:
639+
self.verify_post_state(
640+
t8n, t8n_state=alloc, expected_state=block.expected_post_state
641+
)
642+
625643
fcu_version = fork.engine_forkchoice_updated_version(header.number, header.timestamp)
626644
assert (
627645
fcu_version is not None
628646
), "A hive fixture was requested but no forkchoice update is defined. The framework should"
629647
" never try to execute this test case."
630648

631-
self.verify_post_state(t8n, alloc)
649+
self.verify_post_state(t8n, t8n_state=alloc)
632650

633651
sync_payload: Optional[FixtureEngineNewPayload] = None
634652
if self.verify_sync:

src/ethereum_test_specs/tests/test_expect.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
from ethereum_test_exceptions import TransactionException
1010
from ethereum_test_fixtures import BlockchainFixture, FixtureFormat, StateFixture
1111
from ethereum_test_forks import Fork, get_deployed_forks
12+
from ethereum_test_tools import Block
1213
from ethereum_test_types import Alloc, Environment, Storage, Transaction, TransactionReceipt
1314

15+
from ..blockchain import BlockchainEngineFixture, BlockchainTest
1416
from ..helpers import (
1517
TransactionExceptionMismatchError,
1618
TransactionReceiptMismatchError,
@@ -349,3 +351,99 @@ def test_transaction_expectation(
349351
else:
350352
with pytest.raises(exception_type) as _:
351353
state_test.generate(request=None, t8n=t8n, fork=fork, fixture_format=fixture_format)
354+
355+
356+
@pytest.mark.parametrize(
357+
"intermediate_state,expected_exception",
358+
[
359+
pytest.param(
360+
{
361+
TestAddress: Account(nonce=1),
362+
Address(0x01): Account(balance=1),
363+
},
364+
None,
365+
id="NoException",
366+
),
367+
pytest.param(
368+
{
369+
TestAddress: Account(nonce=2),
370+
Address(0x01): Account(balance=1),
371+
},
372+
Account.NonceMismatchError,
373+
id="NonceMismatchError",
374+
),
375+
pytest.param(
376+
{
377+
TestAddress: Account(nonce=1),
378+
Address(0x01): Account(balance=2),
379+
},
380+
Account.BalanceMismatchError,
381+
id="BalanceMismatchError",
382+
),
383+
],
384+
)
385+
@pytest.mark.parametrize(
386+
"fixture_format",
387+
[
388+
BlockchainFixture,
389+
BlockchainEngineFixture,
390+
],
391+
)
392+
def test_block_intermediate_state(
393+
pre, t8n, fork, fixture_format: FixtureFormat, intermediate_state, expected_exception
394+
):
395+
"""Validate the state when building blockchain."""
396+
env = Environment()
397+
398+
to = Address(0x01)
399+
tx = Transaction(gas_limit=100_000, to=to, value=1, nonce=0, secret_key=TestPrivateKey)
400+
tx_2 = Transaction(gas_limit=100_000, to=to, value=1, nonce=1, secret_key=TestPrivateKey)
401+
402+
block_1 = Block(
403+
txs=[tx],
404+
expected_post_state={
405+
TestAddress: Account(nonce=1),
406+
to: Account(balance=1),
407+
},
408+
)
409+
410+
block_2 = Block(txs=[], expected_post_state=intermediate_state)
411+
412+
block_3 = Block(
413+
txs=[tx_2],
414+
expected_post_state={
415+
TestAddress: Account(nonce=2),
416+
to: Account(balance=2),
417+
},
418+
)
419+
420+
if expected_exception:
421+
with pytest.raises(expected_exception) as _:
422+
BlockchainTest(
423+
genesis_environment=env,
424+
fork=fork,
425+
t8n=t8n,
426+
pre=pre,
427+
post=block_3.expected_post_state,
428+
blocks=[block_1, block_2, block_3],
429+
).generate(
430+
request=None, # type: ignore
431+
t8n=t8n,
432+
fork=fork,
433+
fixture_format=fixture_format,
434+
)
435+
return
436+
else:
437+
BlockchainTest(
438+
genesis_environment=env,
439+
fork=fork,
440+
t8n=t8n,
441+
pre=pre,
442+
post=block_3.expected_post_state,
443+
blocks=[block_1, block_2, block_3],
444+
).generate(
445+
request=None, # type: ignore
446+
t8n=t8n,
447+
fork=fork,
448+
fixture_format=fixture_format,
449+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Test examples, patterns, templates to use in .py tests."""
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"""Test the SELFDESTRUCT opcode."""
2+
3+
import pytest
4+
5+
from ethereum_test_tools import (
6+
Account,
7+
Alloc,
8+
Block,
9+
BlockchainTestFiller,
10+
Environment,
11+
Transaction,
12+
)
13+
14+
15+
@pytest.mark.valid_from("Frontier")
16+
@pytest.mark.valid_until("Homestead")
17+
def test_block_intermidiate_state(blockchain_test: BlockchainTestFiller, pre: Alloc):
18+
"""Verify intermidiate block states."""
19+
env = Environment()
20+
sender = pre.fund_eoa()
21+
22+
tx = Transaction(gas_limit=100_000, to=None, data=b"", sender=sender, protected=False)
23+
tx_2 = Transaction(gas_limit=100_000, to=None, data=b"", sender=sender, protected=False)
24+
25+
block_1 = Block(
26+
txs=[tx],
27+
expected_post_state={
28+
sender: Account(
29+
nonce=1,
30+
),
31+
},
32+
)
33+
34+
block_2 = Block(txs=[])
35+
36+
block_3 = Block(
37+
txs=[tx_2],
38+
expected_post_state={
39+
sender: Account(
40+
nonce=2,
41+
),
42+
},
43+
)
44+
45+
blockchain_test(
46+
genesis_environment=env,
47+
pre=pre,
48+
post=block_3.expected_post_state,
49+
blocks=[block_1, block_2, block_3],
50+
)

whitelist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ isort
253253
isort's
254254
ispkg
255255
itemName
256+
intermidiate
256257
javascripts
257258
jimporter
258259
joinpath

0 commit comments

Comments
 (0)