Skip to content

Commit c885db3

Browse files
authored
test: Wrap usage of state transition API (#1013)
Wrap the usage of the state transition API from the `evmone::state` for tests so that the new API in `evmone::test` only exposes `TestState` and hides `state::State`. This isolates usage of the `evmone::state` to lower the disturbance caused by API modifications, e.g. in #802.
1 parent da115c7 commit c885db3

7 files changed

Lines changed: 90 additions & 49 deletions

File tree

test/blockchaintest/blockchaintest_runner.cpp

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
#include "../state/mpt_hash.hpp"
66
#include "../state/rlp.hpp"
7-
#include "../state/state.hpp"
8-
#include "../state/system_contracts.hpp"
97
#include "../test/statetest/statetest.hpp"
108
#include "blockchaintest.hpp"
119
#include <gtest/gtest.h>
@@ -30,11 +28,11 @@ struct TransitionResult
3028

3129
namespace
3230
{
33-
TransitionResult apply_block(state::State& state, evmc::VM& vm, const state::BlockInfo& block,
31+
TransitionResult apply_block(TestState& state, evmc::VM& vm, const state::BlockInfo& block,
3432
const std::vector<state::Transaction>& txs, evmc_revision rev,
3533
std::optional<int64_t> block_reward)
3634
{
37-
state::system_call(state, block, rev, vm);
35+
system_call(state, block, rev, vm);
3836

3937
std::vector<state::Log> txs_logs;
4038
int64_t block_gas_left = block.gas_limit;
@@ -50,7 +48,7 @@ TransitionResult apply_block(state::State& state, evmc::VM& vm, const state::Blo
5048
const auto& tx = txs[i];
5149

5250
const auto computed_tx_hash = keccak256(rlp::encode(tx));
53-
auto res = state::transition(state, block, tx, rev, vm, block_gas_left, blob_gas_left);
51+
auto res = test::transition(state, block, tx, rev, vm, block_gas_left, blob_gas_left);
5452

5553
if (holds_alternative<std::error_code>(res))
5654
{
@@ -67,15 +65,15 @@ TransitionResult apply_block(state::State& state, evmc::VM& vm, const state::Blo
6765
cumulative_gas_used += receipt.gas_used;
6866
receipt.cumulative_gas_used = cumulative_gas_used;
6967
if (rev < EVMC_BYZANTIUM)
70-
receipt.post_state = state::mpt_hash(TestState{state});
68+
receipt.post_state = state::mpt_hash(state);
7169

7270
block_gas_left -= receipt.gas_used;
7371
blob_gas_left -= tx.blob_gas_used();
7472
receipts.emplace_back(std::move(receipt));
7573
}
7674
}
7775

78-
state::finalize(state, rev, block.coinbase, block_reward, block.ommers, block.withdrawals);
76+
test::finalize(state, rev, block.coinbase, block_reward, block.ommers, block.withdrawals);
7977

8078
const auto bloom = compute_bloom_filter(receipts);
8179
return {std::move(receipts), std::move(rejected_txs), cumulative_gas_used, bloom};
@@ -137,7 +135,7 @@ void run_blockchain_tests(std::span<const BlockchainTest> tests, evmc::VM& vm)
137135
bytes32{});
138136
EXPECT_EQ(c.genesis_block_header.logs_bloom, bytes_view{state::BloomFilter{}});
139137

140-
auto state = c.pre_state.to_intra_state();
138+
auto state = c.pre_state;
141139

142140
std::unordered_map<int64_t, hash256> known_block_hashes{
143141
{c.genesis_block_header.block_number, c.genesis_block_header.hash}};
@@ -158,8 +156,7 @@ void run_blockchain_tests(std::span<const BlockchainTest> tests, evmc::VM& vm)
158156
SCOPED_TRACE(std::string{evmc::to_string(rev)} + '/' + std::to_string(case_index) +
159157
'/' + c.name + '/' + std::to_string(test_block.block_info.number));
160158

161-
EXPECT_EQ(
162-
state::mpt_hash(TestState{state}), test_block.expected_block_header.state_root);
159+
EXPECT_EQ(state::mpt_hash(state), test_block.expected_block_header.state_root);
163160

164161
if (rev >= EVMC_SHANGHAI)
165162
{
@@ -178,14 +175,13 @@ void run_blockchain_tests(std::span<const BlockchainTest> tests, evmc::VM& vm)
178175
// TODO: Add difficulty calculation verification.
179176
}
180177

181-
const TestState post{state};
182178
const auto expected_post_hash =
183179
std::holds_alternative<TestState>(c.expectation.post_state) ?
184180
state::mpt_hash(std::get<TestState>(c.expectation.post_state)) :
185181
std::get<hash256>(c.expectation.post_state);
186-
EXPECT_TRUE(state::mpt_hash(post) == expected_post_hash)
182+
EXPECT_TRUE(state::mpt_hash(state) == expected_post_hash)
187183
<< "Result state:\n"
188-
<< print_state(post)
184+
<< print_state(state)
189185
<< (std::holds_alternative<TestState>(c.expectation.post_state) ?
190186
"\n\nExpected state:\n" +
191187
print_state(std::get<TestState>(c.expectation.post_state)) :

test/state/test_state.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// SPDX-License-Identifier: Apache-2.0
44
#include "test_state.hpp"
55
#include "state.hpp"
6+
#include "system_contracts.hpp"
67

78
namespace evmone::test
89
{
@@ -31,4 +32,30 @@ state::State TestState::to_intra_state() const
3132
}
3233
return intra_state;
3334
}
35+
36+
[[nodiscard]] std::variant<state::TransactionReceipt, std::error_code> transition(TestState& state,
37+
const state::BlockInfo& block, const state::Transaction& tx, evmc_revision rev, evmc::VM& vm,
38+
int64_t block_gas_left, int64_t blob_gas_left)
39+
{
40+
auto intra_state = state.to_intra_state();
41+
auto res = state::transition(intra_state, block, tx, rev, vm, block_gas_left, blob_gas_left);
42+
state = TestState{intra_state};
43+
return res;
44+
}
45+
46+
void finalize(TestState& state, evmc_revision rev, const address& coinbase,
47+
std::optional<uint64_t> block_reward, std::span<const state::Ommer> ommers,
48+
std::span<const state::Withdrawal> withdrawals)
49+
{
50+
auto intra_state = state.to_intra_state();
51+
state::finalize(intra_state, rev, coinbase, block_reward, ommers, withdrawals);
52+
state = TestState{intra_state};
53+
}
54+
55+
void system_call(TestState& state, const state::BlockInfo& block, evmc_revision rev, evmc::VM& vm)
56+
{
57+
auto intra_state = state.to_intra_state();
58+
state::system_call(intra_state, block, rev, vm);
59+
state = TestState{intra_state};
60+
}
3461
} // namespace evmone::test

test/state/test_state.hpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@
66
#include <evmc/evmc.hpp>
77
#include <intx/intx.hpp>
88
#include <map>
9+
#include <span>
10+
#include <variant>
911

1012
namespace evmone
1113
{
1214
namespace state
1315
{
16+
struct BlockInfo;
17+
struct Ommer;
18+
struct Transaction;
19+
struct TransactionReceipt;
20+
struct Withdrawal;
1421
class State;
15-
}
22+
} // namespace state
1623

1724
namespace test
1825
{
@@ -63,5 +70,18 @@ class TestState : public std::map<address, TestAccount>
6370
[[nodiscard]] state::State to_intra_state() const;
6471
};
6572

73+
/// Wrapping of state::transition() which operates on TestState.
74+
[[nodiscard]] std::variant<state::TransactionReceipt, std::error_code> transition(TestState& state,
75+
const state::BlockInfo& block, const state::Transaction& tx, evmc_revision rev, evmc::VM& vm,
76+
int64_t block_gas_left, int64_t blob_gas_left);
77+
78+
/// Wrapping of state::finalize() which operates on TestState.
79+
void finalize(TestState& state, evmc_revision rev, const address& coinbase,
80+
std::optional<uint64_t> block_reward, std::span<const state::Ommer> ommers,
81+
std::span<const state::Withdrawal> withdrawals);
82+
83+
/// Wrapping of state::system_call() which operates on TestState.
84+
void system_call(TestState& state, const state::BlockInfo& block, evmc_revision rev, evmc::VM& vm);
85+
6686
} // namespace test
6787
} // namespace evmone

test/statetest/statetest_runner.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_su
2525

2626
const auto& expected = cases[case_index];
2727
const auto tx = test.multi_tx.get(expected.indexes);
28-
auto state = test.pre_state.to_intra_state();
28+
auto state = test.pre_state;
2929

30-
const auto res = state::transition(state, test.block, tx, rev, vm, test.block.gas_limit,
30+
const auto res = test::transition(state, test.block, tx, rev, vm, test.block.gas_limit,
3131
state::BlockInfo::MAX_BLOB_GAS_PER_BLOCK);
3232

3333
// Finalize block with reward 0.
34-
state::finalize(state, rev, test.block.coinbase, 0, {}, {});
34+
test::finalize(state, rev, test.block.coinbase, 0, {}, {});
3535

36-
const auto state_root = state::mpt_hash(TestState{state});
36+
const auto state_root = state::mpt_hash(state);
3737

3838
if (trace_summary)
3939
{

test/t8n/t8n.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#include "../state/ethash_difficulty.hpp"
77
#include "../state/mpt_hash.hpp"
88
#include "../state/rlp.hpp"
9-
#include "../state/system_contracts.hpp"
109
#include "../statetest/statetest.hpp"
1110
#include "../utils/utils.hpp"
1211
#include <evmone/evmone.h>
@@ -76,14 +75,13 @@ int main(int argc, const char* argv[])
7675
}
7776

7877
state::BlockInfo block;
79-
state::State state;
78+
TestState state;
8079

8180
if (!alloc_file.empty())
8281
{
8382
const auto j = json::json::parse(std::ifstream{alloc_file}, nullptr, false);
84-
const auto test_state = test::from_json<TestState>(j);
85-
validate_state(test_state, rev);
86-
state = test_state.to_intra_state();
83+
state = from_json<TestState>(j);
84+
validate_state(state, rev);
8785
}
8886
if (!env_file.empty())
8987
{
@@ -135,7 +133,7 @@ int main(int argc, const char* argv[])
135133
j_result["receipts"] = json::json::array();
136134
j_result["rejected"] = json::json::array();
137135

138-
state::system_call(state, block, rev, vm);
136+
test::system_call(state, block, rev, vm);
139137

140138
for (size_t i = 0; i < j_txs.size(); ++i)
141139
{
@@ -171,7 +169,7 @@ int main(int argc, const char* argv[])
171169
}
172170

173171
auto res =
174-
state::transition(state, block, tx, rev, vm, block_gas_left, blob_gas_left);
172+
test::transition(state, block, tx, rev, vm, block_gas_left, blob_gas_left);
175173

176174
if (holds_alternative<std::error_code>(res))
177175
{
@@ -196,7 +194,7 @@ int main(int argc, const char* argv[])
196194
cumulative_gas_used += receipt.gas_used;
197195
receipt.cumulative_gas_used = cumulative_gas_used;
198196
if (rev < EVMC_BYZANTIUM)
199-
receipt.post_state = state::mpt_hash(TestState{state});
197+
receipt.post_state = state::mpt_hash(state);
200198
j_receipt["cumulativeGasUsed"] = hex0x(cumulative_gas_used);
201199

202200
j_receipt["blockHash"] = hex0x(bytes32{});
@@ -218,11 +216,11 @@ int main(int argc, const char* argv[])
218216
}
219217
}
220218

221-
state::finalize(
219+
test::finalize(
222220
state, rev, block.coinbase, block_reward, block.ommers, block.withdrawals);
223221

224222
j_result["logsHash"] = hex0x(logs_hash(txs_logs));
225-
j_result["stateRoot"] = hex0x(state::mpt_hash(TestState{state}));
223+
j_result["stateRoot"] = hex0x(state::mpt_hash(state));
226224
}
227225

228226
j_result["logsBloom"] = hex0x(compute_bloom_filter(receipts));

test/unittests/state_system_call_test.cpp

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <gtest/gtest.h>
77
#include <test/state/state.hpp>
88
#include <test/state/system_contracts.hpp>
9+
#include <test/state/test_state.hpp>
910
#include <test/utils/bytecode.hpp>
1011

1112
using namespace evmc::literals;
@@ -16,15 +17,15 @@ class state_system_call : public testing::Test
1617
{
1718
protected:
1819
evmc::VM vm{evmc_create_evmone()};
19-
State state;
20+
TestState state;
2021
};
2122

2223
TEST_F(state_system_call, non_existient)
2324
{
2425
// Use MAX revision to invoke all activate system contracts.
2526
system_call(state, {}, EVMC_MAX_REVISION, vm);
2627

27-
EXPECT_EQ(state.get_accounts().size(), 0) << "State must remain unchanged";
28+
EXPECT_EQ(state.size(), 0) << "State must remain unchanged";
2829
}
2930

3031
TEST_F(state_system_call, beacon_roots)
@@ -35,14 +36,14 @@ TEST_F(state_system_call, beacon_roots)
3536

3637
system_call(state, block, EVMC_CANCUN, vm);
3738

38-
ASSERT_EQ(state.get_accounts().size(), 1);
39-
EXPECT_EQ(state.find(SYSTEM_ADDRESS), nullptr);
40-
EXPECT_EQ(state.get(BEACON_ROOTS_ADDRESS).nonce, 0);
41-
EXPECT_EQ(state.get(BEACON_ROOTS_ADDRESS).balance, 0);
42-
const auto& storage = state.get(BEACON_ROOTS_ADDRESS).storage;
39+
ASSERT_EQ(state.size(), 1);
40+
EXPECT_FALSE(state.contains(SYSTEM_ADDRESS));
41+
EXPECT_EQ(state.at(BEACON_ROOTS_ADDRESS).nonce, 0);
42+
EXPECT_EQ(state.at(BEACON_ROOTS_ADDRESS).balance, 0);
43+
const auto& storage = state.at(BEACON_ROOTS_ADDRESS).storage;
4344
ASSERT_EQ(storage.size(), 2);
44-
EXPECT_EQ(storage.at(0x01_bytes32).current, block.parent_beacon_block_root);
45-
EXPECT_EQ(storage.at(0x00_bytes32).current, to_bytes32(SYSTEM_ADDRESS));
45+
EXPECT_EQ(storage.at(0x01_bytes32), block.parent_beacon_block_root);
46+
EXPECT_EQ(storage.at(0x00_bytes32), to_bytes32(SYSTEM_ADDRESS));
4647
}
4748

4849
TEST_F(state_system_call, history_storage)
@@ -55,12 +56,12 @@ TEST_F(state_system_call, history_storage)
5556

5657
system_call(state, block, EVMC_PRAGUE, vm);
5758

58-
ASSERT_EQ(state.get_accounts().size(), 1);
59-
EXPECT_EQ(state.find(SYSTEM_ADDRESS), nullptr);
60-
EXPECT_EQ(state.get(HISTORY_STORAGE_ADDRESS).nonce, 0);
61-
EXPECT_EQ(state.get(HISTORY_STORAGE_ADDRESS).balance, 0);
62-
const auto& storage = state.get(HISTORY_STORAGE_ADDRESS).storage;
59+
ASSERT_EQ(state.size(), 1);
60+
EXPECT_FALSE(state.contains(SYSTEM_ADDRESS));
61+
EXPECT_EQ(state.at(HISTORY_STORAGE_ADDRESS).nonce, 0);
62+
EXPECT_EQ(state.at(HISTORY_STORAGE_ADDRESS).balance, 0);
63+
const auto& storage = state.at(HISTORY_STORAGE_ADDRESS).storage;
6364
ASSERT_EQ(storage.size(), 2);
64-
EXPECT_EQ(storage.at(bytes32{NUMBER}).current, PREV_BLOCKHASH);
65-
EXPECT_EQ(storage.at(0x00_bytes32).current, to_bytes32(SYSTEM_ADDRESS));
65+
EXPECT_EQ(storage.at(bytes32{NUMBER}), PREV_BLOCKHASH);
66+
EXPECT_EQ(storage.at(0x00_bytes32), to_bytes32(SYSTEM_ADDRESS));
6667
}

test/unittests/state_transition.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ void state_transition::TearDown()
4848

4949
// Execution:
5050

51+
auto state = pre;
5152
const auto trace = !expect.trace.empty();
5253
auto& selected_vm = trace ? tracing_vm : vm;
5354

@@ -56,12 +57,10 @@ void state_transition::TearDown()
5657
if (trace)
5758
trace_capture.emplace();
5859

59-
auto intra_state = pre.to_intra_state();
60-
const auto res = state::transition(intra_state, block, tx, rev, selected_vm, block.gas_limit,
60+
const auto res = test::transition(state, block, tx, rev, selected_vm, block.gas_limit,
6161
state::BlockInfo::MAX_BLOB_GAS_PER_BLOCK);
62-
state::finalize(
63-
intra_state, rev, block.coinbase, block_reward, block.ommers, block.withdrawals);
64-
TestState post{intra_state};
62+
test::finalize(state, rev, block.coinbase, block_reward, block.ommers, block.withdrawals);
63+
const auto& post = state;
6564

6665
if (const auto expected_error = make_error_code(expect.tx_error))
6766
{

0 commit comments

Comments
 (0)