Skip to content

Commit ecdd703

Browse files
hugo-dcchfast
andcommitted
statetest: --trace-summary CLI option
Add --trace-summary option that only outputs a trace summary, including the final state root. Co-authored-by: Paweł Bylica <pawel@ethereum.org>
1 parent b1faba9 commit ecdd703

4 files changed

Lines changed: 54 additions & 16 deletions

File tree

test/integration/statetest/CMakeLists.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,23 @@ add_test(
7979
NAME ${PREFIX}/trace
8080
COMMAND evmone-statetest ${TESTS1}/SuiteA/test1.json --trace
8181
)
82+
set(EXPECTED_TRACE [[
83+
{"pc":0,"op":96,"gas":"0x5c878","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"}
84+
{"pc":2,"op":96,"gas":"0x5c875","gasCost":"0x3","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"PUSH1"}
85+
{"pc":4,"op":1,"gas":"0x5c872","gasCost":"0x3","memSize":0,"stack":["0x1","0x1"],"depth":1,"refund":0,"opName":"ADD"}
86+
{"pc":5,"op":96,"gas":"0x5c86f","gasCost":"0x3","memSize":0,"stack":["0x2"],"depth":1,"refund":0,"opName":"PUSH1"}
87+
{"pc":7,"op":85,"gas":"0x5c86c","gasCost":"0x0","memSize":0,"stack":["0x2","0x0"],"depth":1,"refund":0,"opName":"SSTORE"}
88+
{"pc":8,"op":0,"gas":"0x57218","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"}
89+
{"pass":true,"gasUsed":"0xa868","stateRoot":"0xe8010ce590f401c9d61fef8ab05bea9bcec24281b795e5868809bc4e515aa530"}
90+
]])
91+
# Escape regex special characters.
92+
string(REPLACE "{" "\\{" EXPECTED_TRACE ${EXPECTED_TRACE})
93+
string(REPLACE "}" "\\}" EXPECTED_TRACE ${EXPECTED_TRACE})
94+
string(REPLACE "[" "\\[" EXPECTED_TRACE ${EXPECTED_TRACE})
95+
string(REPLACE "]" "\\]" EXPECTED_TRACE ${EXPECTED_TRACE})
8296
set_tests_properties(
8397
${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"\}]=]
98+
PASS_REGULAR_EXPRESSION ${EXPECTED_TRACE}
8599
)
86100

87101
add_test(

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_runner.cpp

Lines changed: 19 additions & 2 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,29 @@ 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
3956
EXPECT_TRUE(expected.exception);
4057

41-
EXPECT_EQ(state::mpt_hash(state.get_accounts()), expected.state_hash);
58+
EXPECT_EQ(state_root, expected.state_hash);
4259
}
4360
}
4461
}

0 commit comments

Comments
 (0)