Skip to content

Commit 33c66e7

Browse files
authored
statetest: Add changes required to be executed in goevmlab (#658)
- Add `--trace-summary` CLI flag to output state root. - Make `_info` JSON section optional (goevmlab is not providing this field). - Implement convention for `Host::get_block_hash()` (done in #698).
2 parents c931df7 + 184b2c4 commit 33c66e7

File tree

7 files changed

+114
-21
lines changed

7 files changed

+114
-21
lines changed

test/integration/statetest/CMakeLists.txt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ set(PREFIX ${PREFIX}/statetest)
88
set(TESTS1 ${CMAKE_CURRENT_SOURCE_DIR}/tests1)
99
set(TESTS2 ${CMAKE_CURRENT_SOURCE_DIR}/tests2)
1010
set(TESTS_EOF ${CMAKE_CURRENT_SOURCE_DIR}/eof)
11+
set(TESTS_TX ${CMAKE_CURRENT_SOURCE_DIR}/tx)
1112

1213
add_test(
1314
NAME ${PREFIX}/no_arguments
@@ -79,9 +80,23 @@ add_test(
7980
NAME ${PREFIX}/trace
8081
COMMAND evmone-statetest ${TESTS1}/SuiteA/test1.json --trace
8182
)
83+
set(EXPECTED_TRACE [[
84+
{"pc":0,"op":96,"gas":"0x5c878","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"}
85+
{"pc":2,"op":96,"gas":"0x5c875","gasCost":"0x3","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"PUSH1"}
86+
{"pc":4,"op":1,"gas":"0x5c872","gasCost":"0x3","memSize":0,"stack":["0x1","0x1"],"depth":1,"refund":0,"opName":"ADD"}
87+
{"pc":5,"op":96,"gas":"0x5c86f","gasCost":"0x3","memSize":0,"stack":["0x2"],"depth":1,"refund":0,"opName":"PUSH1"}
88+
{"pc":7,"op":85,"gas":"0x5c86c","gasCost":"0x0","memSize":0,"stack":["0x2","0x0"],"depth":1,"refund":0,"opName":"SSTORE"}
89+
{"pc":8,"op":0,"gas":"0x57218","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"}
90+
{"pass":true,"gasUsed":"0xa868","stateRoot":"0xe8010ce590f401c9d61fef8ab05bea9bcec24281b795e5868809bc4e515aa530"}
91+
]])
92+
# Escape regex special characters.
93+
string(REPLACE "{" "\\{" EXPECTED_TRACE ${EXPECTED_TRACE})
94+
string(REPLACE "}" "\\}" EXPECTED_TRACE ${EXPECTED_TRACE})
95+
string(REPLACE "[" "\\[" EXPECTED_TRACE ${EXPECTED_TRACE})
96+
string(REPLACE "]" "\\]" EXPECTED_TRACE ${EXPECTED_TRACE})
8297
set_tests_properties(
8398
${PREFIX}/trace PROPERTIES
84-
PASS_REGULAR_EXPRESSION [=[\{"pc":4,"op":1,"gas":"0x5c872","gasCost":"0x3","memSize":0,"stack":\["0x1","0x1"\],"depth":1,"refund":0,"opName":"ADD"\}]=]
99+
PASS_REGULAR_EXPRESSION ${EXPECTED_TRACE}
85100
)
86101

87102
add_test(
@@ -92,3 +107,12 @@ set_tests_properties(
92107
${PREFIX}/invalid_eof_in_state PROPERTIES
93108
PASS_REGULAR_EXPRESSION "EOF container at 0x0000000000000000000000000000000000bade0f is invalid"
94109
)
110+
111+
add_test(
112+
NAME ${PREFIX}/tx_invalid_nonce
113+
COMMAND evmone-statetest ${TESTS_TX}/invalid_nonce.json
114+
)
115+
set_tests_properties(
116+
${PREFIX}/tx_invalid_nonce PROPERTIES
117+
PASS_REGULAR_EXPRESSION "unexpected invalid transaction: nonce too high"
118+
)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"invalid_nonce": {
3+
"env": {
4+
"currentBaseFee": "0x0a",
5+
"currentCoinbase": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
6+
"currentDifficulty": "0x020000",
7+
"currentGasLimit": "0xff112233445566",
8+
"currentNumber": "0x01",
9+
"currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000",
10+
"currentTimestamp": "0x03e8"
11+
},
12+
"post": {
13+
"Shanghai": [
14+
{
15+
"hash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
16+
"indexes": {
17+
"data": 0,
18+
"gas": 0,
19+
"value": 0
20+
},
21+
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
22+
}
23+
]
24+
},
25+
"pre": {},
26+
"transaction": {
27+
"data": [
28+
"0x"
29+
],
30+
"gasLimit": [
31+
"0x00"
32+
],
33+
"gasPrice": "0x0a",
34+
"nonce": "0x01",
35+
"sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
36+
"to": "0x00",
37+
"value": [
38+
"0x00"
39+
]
40+
}
41+
}
42+
}

test/statetest/statetest.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,28 @@ class StateTest : public testing::Test
1414
{
1515
fs::path m_json_test_file;
1616
evmc::VM& m_vm;
17+
bool m_trace = false;
1718

1819
public:
19-
explicit StateTest(fs::path json_test_file, evmc::VM& vm) noexcept
20-
: m_json_test_file{std::move(json_test_file)}, m_vm{vm}
20+
explicit StateTest(fs::path json_test_file, evmc::VM& vm, bool trace) noexcept
21+
: m_json_test_file{std::move(json_test_file)}, m_vm{vm}, m_trace{trace}
2122
{}
2223

2324
void TestBody() final
2425
{
2526
std::ifstream f{m_json_test_file};
26-
evmone::test::run_state_test(evmone::test::load_state_test(f), m_vm);
27+
evmone::test::run_state_test(evmone::test::load_state_test(f), m_vm, m_trace);
2728
}
2829
};
2930

30-
void register_test(const std::string& suite_name, const fs::path& file, evmc::VM& vm)
31+
void register_test(const std::string& suite_name, const fs::path& file, evmc::VM& vm, bool trace)
3132
{
3233
testing::RegisterTest(suite_name.c_str(), file.stem().string().c_str(), nullptr, nullptr,
3334
file.string().c_str(), 0,
34-
[file, &vm]() -> testing::Test* { return new StateTest(file, vm); });
35+
[file, &vm, trace]() -> testing::Test* { return new StateTest(file, vm, trace); });
3536
}
3637

37-
void register_test_files(const fs::path& root, evmc::VM& vm)
38+
void register_test_files(const fs::path& root, evmc::VM& vm, bool trace)
3839
{
3940
if (is_directory(root))
4041
{
@@ -46,11 +47,11 @@ void register_test_files(const fs::path& root, evmc::VM& vm)
4647
std::sort(test_files.begin(), test_files.end());
4748

4849
for (const auto& p : test_files)
49-
register_test(fs::relative(p, root).parent_path().string(), p, vm);
50+
register_test(fs::relative(p, root).parent_path().string(), p, vm, trace);
5051
}
5152
else // Treat as a file.
5253
{
53-
register_test(root.parent_path().string(), root, vm);
54+
register_test(root.parent_path().string(), root, vm, trace);
5455
}
5556
}
5657
} // namespace
@@ -80,18 +81,21 @@ int main(int argc, char* argv[])
8081
->required()
8182
->check(CLI::ExistingPath);
8283

83-
bool trace_flag = false;
84-
app.add_flag("--trace", trace_flag, "Enable EVM tracing");
84+
bool trace = false;
85+
bool trace_summary = false;
86+
const auto trace_opt = app.add_flag("--trace", trace, "Enable EVM tracing");
87+
app.add_flag("--trace-summary", trace_summary, "Output trace summary only")
88+
->excludes(trace_opt);
8589

8690
CLI11_PARSE(app, argc, argv);
8791

8892
evmc::VM vm{evmc_create_evmone(), {{"O", "0"}}};
8993

90-
if (trace_flag)
94+
if (trace)
9195
vm.set_option("trace", "1");
9296

9397
for (const auto& p : paths)
94-
register_test_files(p, vm);
98+
register_test_files(p, vm, trace || trace_summary);
9599

96100
return RUN_ALL_TESTS();
97101
}

test/statetest/statetest.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ StateTransitionTest load_state_test(std::istream& input);
9292
/// Throws exception on any invalid EOF in state.
9393
void validate_deployed_code(const state::State& state, evmc_revision rev);
9494

95-
void run_state_test(const StateTransitionTest& test, evmc::VM& vm);
95+
/// Execute the state @p test using the @p vm.
96+
///
97+
/// @param trace_summary Output execution summary to the default trace stream.
98+
void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_summary);
9699

97100
/// Computes the hash of the RLP-encoded list of transaction logs.
98101
/// This method is only used in tests.

test/statetest/statetest_loader.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,10 +397,13 @@ static void from_json(const json::json& j, StateTransitionTest& o)
397397

398398
o.block = from_json<state::BlockInfo>(j_t.at("env"));
399399

400-
if (const auto& info = j_t.at("_info"); info.contains("labels"))
400+
if (const auto info_it = j_t.find("_info"); info_it != j_t.end())
401401
{
402-
for (const auto& [j_id, j_label] : info.at("labels").items())
403-
o.input_labels.emplace(from_json<uint64_t>(j_id), j_label);
402+
if (const auto labels_it = info_it->find("labels"); labels_it != info_it->end())
403+
{
404+
for (const auto& [j_id, j_label] : labels_it->items())
405+
o.input_labels.emplace(from_json<uint64_t>(j_id), j_label);
406+
}
404407
}
405408

406409
for (const auto& [rev_name, expectations] : j_t.at("post").items())

test/statetest/statetest_runner.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace evmone::test
1111
{
12-
void run_state_test(const StateTransitionTest& test, evmc::VM& vm)
12+
void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_summary)
1313
{
1414
for (const auto& [rev, cases] : test.cases)
1515
{
@@ -33,12 +33,30 @@ void run_state_test(const StateTransitionTest& test, evmc::VM& vm)
3333
// Finalize block with reward 0.
3434
state::finalize(state, rev, test.block.coinbase, 0, {}, {});
3535

36+
const auto state_root = state::mpt_hash(state.get_accounts());
37+
38+
if (trace_summary)
39+
{
40+
std::clog << '{';
41+
if (holds_alternative<state::TransactionReceipt>(res)) // if tx valid
42+
{
43+
const auto& r = get<state::TransactionReceipt>(res);
44+
if (r.status == EVMC_SUCCESS)
45+
std::clog << R"("pass":true)";
46+
else
47+
std::clog << R"("pass":false,"error":")" << r.status << '"';
48+
std::clog << R"(,"gasUsed":"0x)" << std::hex << r.gas_used << R"(",)";
49+
}
50+
std::clog << R"("stateRoot":"0x)" << hex(state_root) << "\"}\n";
51+
}
52+
3653
if (holds_alternative<state::TransactionReceipt>(res))
3754
EXPECT_EQ(logs_hash(get<state::TransactionReceipt>(res).logs), expected.logs_hash);
3855
else
39-
EXPECT_TRUE(expected.exception);
56+
EXPECT_TRUE(expected.exception)
57+
<< "unexpected invalid transaction: " << get<std::error_code>(res).message();
4058

41-
EXPECT_EQ(state::mpt_hash(state.get_accounts()), expected.state_hash);
59+
EXPECT_EQ(state_root, expected.state_hash);
4260
}
4361
}
4462
}

test/unittests/statetest_loader_test.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ TEST(statetest_loader, load_minimal_test)
7474
{
7575
std::istringstream s{R"({
7676
"test": {
77-
"_info": {},
7877
"pre": {},
7978
"transaction": {
8079
"gasPrice": "",

0 commit comments

Comments
 (0)