Skip to content

Commit

Permalink
more unit tests for post state verification
Browse files Browse the repository at this point in the history
expect section wip
  • Loading branch information
winsvega committed Dec 4, 2023
1 parent 398003d commit 19d709c
Show file tree
Hide file tree
Showing 2 changed files with 386 additions and 11 deletions.
373 changes: 373 additions & 0 deletions src/ethereum_test_tools/tests/test_filler_expect_account.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,373 @@
"""
Tests for the fixture `post` (expect) section.
"""

from collections import namedtuple
from typing import Any, Mapping, Optional

import pytest

from ethereum_test_forks import Fork, Shanghai
from evm_transition_tool import GethTransitionTool

from ..common import Account, Environment, Transaction
from ..common.types import Storage
from ..filling import fill_test
from ..spec import BaseTestConfig, StateTest
from ..vm.opcode import Opcodes as Op

ExpectSectionIndex = namedtuple("ExpectSectionIndex", ["d", "g", "v", "fork"])


class ExpectSection:
"""Manage expected post states for state tests transactions"""

def __init__(self):
self.sections: list[tuple[ExpectSectionIndex, dict[str, Account]]] = []

def add_expect(self, ind: ExpectSectionIndex, expect: dict[str, Account]) -> None:
"""Adds a section with a given indexes and expect dictionary."""
self.sections.append((ind, expect))

def get_expect(self, tx_ind: ExpectSectionIndex) -> Optional[dict[str, Account]]:
"""Returns the element associated with the given id, if it exists."""
for section_ind, section in self.sections:
if (
(tx_ind.d in section_ind.d or section_ind.d == -1)
and (tx_ind.g in section_ind.g or section_ind.g == -1)
and (tx_ind.v in section_ind.v or section_ind.v == -1)
):
return section
return None


test_fork = Shanghai
sender_address = "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
test_address = "0x1000000000000000000000000000000000000000"
test_transaction = Transaction(
ty=0x0,
chain_id=0x0,
nonce=0,
to=test_address,
gas_limit=100000000,
gas_price=10,
protected=False,
)


def run_test(
pre: Mapping[Any, Any], post: Mapping[Any, Any], tx: Transaction, fork: Fork, exception: Any
) -> Optional[pytest.ExceptionInfo]:
"""
Perform the test execution and post state verification given pre and post
"""
state_test = StateTest(
env=Environment(),
pre=pre,
post=post,
txs=[tx],
tag="post_storage_value_mismatch",
base_test_config=BaseTestConfig(enable_hive=False),
)

t8n = GethTransitionTool()

e_info: pytest.ExceptionInfo
if exception is not None:
with pytest.raises(exception) as e_info:
fixture = {
f"000/my_chain_id_test/{fork}": fill_test(
t8n=t8n,
test_spec=state_test,
fork=fork,
spec=None,
),
}
return e_info
else:
fixture = {
f"000/my_chain_id_test/{fork}": fill_test(
t8n=t8n,
test_spec=state_test,
fork=fork,
spec=None,
),
}
return None


def test_expect_section_example():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(nonce=1, code=Op.SSTORE(0, Op.CALLVALUE)),
}

post_1 = {
test_address: Account(storage={"0x00": "0x09"}),
}
post_2 = {
test_address: Account(storage={"0x00": "0x03"}),
}

expect_section = ExpectSection()
expect_section.add_expect(ExpectSectionIndex(d=[0], g=[0], v=[0, 1], fork=Shanghai), post_1)
# expect_section.add_expect(ExpectSectionIndex(d=0, g=0, v=1, fork=Shanghai), post_2)

transaction = test_transaction
transaction.value = 1
tx_index = ExpectSectionIndex(d=0, g=0, v=0, fork=Shanghai)
e_info = run_test(
pre, expect_section.get_expect(tx_index), transaction, test_fork, Storage.KeyValueMismatch
)
assert e_info.value.want == 9
assert e_info.value.got == 1
assert e_info.value.key == 0
assert e_info.value.address == test_address
assert "incorrect value in address" in str(e_info.value)

transaction = test_transaction
transaction.value = 2
tx_index = ExpectSectionIndex(d=0, g=0, v=1, fork=Shanghai)
e_info = run_test(
pre, expect_section.get_expect(tx_index), transaction, test_fork, Storage.KeyValueMismatch
)
assert e_info.value.want == 9
assert e_info.value.got == 2
assert e_info.value.key == 0
assert e_info.value.address == test_address
assert "incorrect value in address" in str(e_info.value)


def test_post_account_mismatch_nonce():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(nonce=1),
}

post = {
test_address: Account(nonce=2),
}

e_info = run_test(pre, post, test_transaction, test_fork, Account.NonceMismatch)
assert e_info.value.want == 2
assert e_info.value.got == 1
assert e_info.value.address == test_address
assert "unexpected nonce for account" in str(e_info.value)


def test_post_account_mismatch_nonce_a():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(nonce=1),
}

post = {
test_address: Account(),
}

run_test(pre, post, test_transaction, test_fork, None)


def test_post_account_mismatch_nonce_b():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(nonce=1),
}

post = {
test_address: Account(nonce=0),
}

e_info = run_test(pre, post, test_transaction, test_fork, Account.NonceMismatch)
assert e_info.value.want == 0
assert e_info.value.got == 1
assert e_info.value.address == test_address
assert "unexpected nonce for account" in str(e_info.value)


def test_post_account_mismatch_code():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(code="0x02"),
}

post = {
test_address: Account(code="0x01"),
}

e_info = run_test(pre, post, test_transaction, test_fork, Account.CodeMismatch)
assert e_info.value.want == "0x01"
assert e_info.value.got == "0x02"
assert e_info.value.address == test_address
assert "unexpected code for account" in str(e_info.value)


def test_post_account_mismatch_code_a():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(code="0x02"),
}

post = {
test_address: Account(),
}

run_test(pre, post, test_transaction, test_fork, None)


def test_post_account_mismatch_code_b():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(code="0x02"),
}

post = {
test_address: Account(code=""),
}

e_info = run_test(pre, post, test_transaction, test_fork, Account.CodeMismatch)
assert e_info.value.want == "0x"
assert e_info.value.got == "0x02"
assert e_info.value.address == test_address
assert "unexpected code for account" in str(e_info.value)


def test_post_account_mismatch_balance():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(balance=1),
}

post = {
test_address: Account(balance=2),
}

test_transaction.value = 0
e_info = run_test(pre, post, test_transaction, test_fork, Account.BalanceMismatch)
assert e_info.value.want == 2
assert e_info.value.got == 1
assert e_info.value.address == test_address
assert "unexpected balance for account" in str(e_info.value)


def test_post_account_mismatch_balance_a():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(balance=1),
}

post = {
test_address: Account(),
}

test_transaction.value = 0
run_test(pre, post, test_transaction, test_fork, None)


def test_post_account_mismatch_balance_b():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(balance=1),
}

post = {
test_address: Account(balance=0),
}

e_info = run_test(pre, post, test_transaction, test_fork, Account.BalanceMismatch)
assert e_info.value.want == 0
assert e_info.value.got == 1
assert e_info.value.address == test_address
assert "unexpected balance for account" in str(e_info.value)


def test_post_account_mismatch_account():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(balance=1),
}

post = {
test_address: Account(),
}

run_test(pre, post, test_transaction, test_fork, None)


def test_post_account_mismatch_account_a():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(balance=1),
}

post = {
0x1000000000000000000000000000000000000001: Account(),
}

e_info = run_test(pre, post, test_transaction, test_fork, Exception)
assert "expected account not found" in str(e_info.value)


def test_post_account_mismatch_account_b():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(balance=1),
}

post = {}

run_test(pre, post, test_transaction, test_fork, None)


def test_post_account_mismatch_account_c():
"""
Test `ethereum_test.filler.fill_fixtures` with `StateTest` and post state verification.
"""
pre = {
sender_address: Account(balance=1000000000000000000000),
test_address: Account(balance=1),
}

post = {test_address: Account.NONEXISTENT}

e_info = run_test(pre, post, test_transaction, test_fork, Exception)
assert "found unexpected account" in str(e_info.value)
Loading

0 comments on commit 19d709c

Please sign in to comment.