diff --git a/test/statetest/statetest.hpp b/test/statetest/statetest.hpp
index 5ad6a1d594..bdf3b1815b 100644
--- a/test/statetest/statetest.hpp
+++ b/test/statetest/statetest.hpp
@@ -95,9 +95,11 @@ json::json to_json(const std::unordered_map
& accounts);
StateTransitionTest load_state_test(std::istream& input);
-/// Validates deployed EOF containers before running state test.
-/// Throws exception on any invalid EOF in state.
-void validate_deployed_code(const state::State& state, evmc_revision rev);
+/// Validates an Ethereum state:
+/// - checks that there are no zero-value storage entries,
+/// - checks that there are no invalid EOF codes.
+/// Throws std::invalid_argument exception.
+void validate_state(const state::State& state, evmc_revision rev);
/// Execute the state @p test using the @p vm.
///
diff --git a/test/statetest/statetest_loader.cpp b/test/statetest/statetest_loader.cpp
index a1d9ecce74..90be1dec50 100644
--- a/test/statetest/statetest_loader.cpp
+++ b/test/statetest/statetest_loader.cpp
@@ -271,9 +271,9 @@ state::State from_json(const json::json& j)
{
for (const auto& [j_key, j_value] : storage_it->items())
{
- const auto value = from_json(j_value);
- acc.storage.insert(
- {from_json(j_key), {.current = value, .original = value}});
+ if (const auto value = from_json(j_value); !is_zero(value))
+ acc.storage.insert(
+ {from_json(j_key), {.current = value, .original = value}});
}
}
}
@@ -434,10 +434,12 @@ StateTransitionTest load_state_test(std::istream& input)
return json::json::parse(input).get();
}
-void validate_deployed_code(const state::State& state, evmc_revision rev)
+void validate_state(const state::State& state, evmc_revision rev)
{
for (const auto& [addr, acc] : state.get_accounts())
{
+ // TODO: Check for empty accounts after Paris.
+ // https://github.com/ethereum/tests/issues/1331
if (is_eof_container(acc.code))
{
if (rev >= EVMC_PRAGUE)
@@ -451,6 +453,16 @@ void validate_deployed_code(const state::State& state, evmc_revision rev)
}
}
}
+
+ for (const auto& [key, value] : acc.storage)
+ {
+ if (is_zero(value.original))
+ {
+ throw std::invalid_argument{"account " + hex0x(addr) +
+ " contains invalid zero-value storage entry " +
+ hex0x(key)};
+ }
+ }
}
}
} // namespace evmone::test
diff --git a/test/statetest/statetest_runner.cpp b/test/statetest/statetest_runner.cpp
index 717e05ec73..8c92e06cc9 100644
--- a/test/statetest/statetest_runner.cpp
+++ b/test/statetest/statetest_runner.cpp
@@ -13,6 +13,7 @@ void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_su
{
for (const auto& [rev, cases] : test.cases)
{
+ validate_state(test.pre_state, rev);
for (size_t case_index = 0; case_index != cases.size(); ++case_index)
{
SCOPED_TRACE(std::string{evmc::to_string(rev)} + '/' + std::to_string(case_index));
@@ -25,8 +26,6 @@ void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_su
const auto tx = test.multi_tx.get(expected.indexes);
auto state = test.pre_state;
- validate_deployed_code(state, rev);
-
const auto res = state::transition(state, test.block, tx, rev, vm, test.block.gas_limit,
state::BlockInfo::MAX_BLOB_GAS_PER_BLOCK);
diff --git a/test/t8n/t8n.cpp b/test/t8n/t8n.cpp
index 37612d34c8..bdad568f17 100644
--- a/test/t8n/t8n.cpp
+++ b/test/t8n/t8n.cpp
@@ -112,19 +112,17 @@ int main(int argc, const char* argv[])
std::vector receipts;
int64_t block_gas_left = block.gas_limit;
- // Validate eof code in pre-state
- if (rev >= EVMC_PRAGUE)
- validate_deployed_code(state, rev);
+ validate_state(state, rev);
// Parse and execute transactions
if (!txs_file.empty())
{
const auto j_txs = json::json::parse(std::ifstream{txs_file});
- evmc::VM vm{evmc_create_evmone(), {{"O", "0"}}};
+ evmc::VM vm{evmc_create_evmone()};
if (trace)
- vm.set_option("trace", "0");
+ vm.set_option("trace", "1");
std::vector txs_logs;
diff --git a/test/unittests/state_transition.cpp b/test/unittests/state_transition.cpp
index 6078a3f912..35a1ad0e78 100644
--- a/test/unittests/state_transition.cpp
+++ b/test/unittests/state_transition.cpp
@@ -40,14 +40,7 @@ class TraceCapture
void state_transition::TearDown()
{
- for (const auto& [addr, acc] : pre.get_accounts())
- {
- if (is_eof_container(acc.code))
- {
- ASSERT_EQ(validate_eof(rev, acc.code), EOFValidationError::success)
- << "invalid EOF in prestate at " << addr;
- }
- }
+ validate_state(pre, rev);
auto state = pre;
const auto trace = !expect.trace.empty();
diff --git a/test/unittests/statetest_loader_test.cpp b/test/unittests/statetest_loader_test.cpp
index ede5fbc9c2..5698c5fb4c 100644
--- a/test/unittests/statetest_loader_test.cpp
+++ b/test/unittests/statetest_loader_test.cpp
@@ -133,14 +133,27 @@ TEST(statetest_loader, load_minimal_test)
EXPECT_EQ(st.input_labels.size(), 0);
}
-TEST(statetest_loader, validate_deployed_code_test)
+TEST(statetest_loader, validate_state_invalid_eof)
{
{
state::State state;
state.insert(0xadd4_address, {.code = "EF0001010000020001000103000100FEDA"_hex});
- EXPECT_THAT([&] { validate_deployed_code(state, EVMC_PRAGUE); },
+ EXPECT_THAT([&] { validate_state(state, EVMC_PRAGUE); },
ThrowsMessage(
"EOF container at 0x000000000000000000000000000000000000add4 is invalid: "
"zero_section_size"));
}
}
+
+TEST(statetest_loader, validate_state_zero_storage_slot)
+{
+ {
+ state::State state;
+ state.insert(0xadd4_address, {.storage = {{0x01_bytes32, {0x00_bytes32}}}});
+ EXPECT_THAT([&] { validate_state(state, EVMC_PRAGUE); },
+ ThrowsMessage(
+ "account 0x000000000000000000000000000000000000add4 contains invalid zero-value "
+ "storage entry "
+ "0x0000000000000000000000000000000000000000000000000000000000000001"));
+ }
+}