Skip to content

Commit fca1128

Browse files
committed
test: Move state test export procedure to testutils
1 parent 44f2c85 commit fca1128

File tree

3 files changed

+134
-113
lines changed

3 files changed

+134
-113
lines changed

test/statetest/statetest.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ state::Transaction from_json<state::Transaction>(const json::json& j);
100100
/// Exports the State (accounts) to JSON format (aka pre/post/alloc state).
101101
json::json to_json(const TestState& state);
102102

103+
/// Export the state test to JSON format.
104+
json::json to_state_test(std::string_view test_name, const state::BlockInfo& block,
105+
state::Transaction& tx, const TestState& pre, evmc_revision rev,
106+
const std::variant<state::TransactionReceipt, std::error_code>& res, const TestState& post);
107+
103108
/// Returns the standardized error message for the transaction validation error.
104109
[[nodiscard]] std::string get_invalid_tx_message(state::ErrorCode errc) noexcept;
105110

test/statetest/statetest_export.cpp

+127
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,27 @@
33
// SPDX-License-Identifier: Apache-2.0
44

55
#include "statetest.hpp"
6+
#include <test/state/mpt_hash.hpp>
67

78
namespace evmone::test
89
{
10+
namespace
11+
{
12+
/// Converts EVM revision to the fork name commonly used in tests.
13+
std::string_view to_test_fork_name(evmc_revision rev) noexcept
14+
{
15+
switch (rev)
16+
{
17+
case EVMC_TANGERINE_WHISTLE:
18+
return "EIP150";
19+
case EVMC_SPURIOUS_DRAGON:
20+
return "EIP158";
21+
default:
22+
return evmc::to_string(rev);
23+
}
24+
}
25+
} // namespace
26+
927
[[nodiscard]] std::string get_invalid_tx_message(state::ErrorCode errc) noexcept
1028
{
1129
using namespace state;
@@ -71,4 +89,113 @@ json::json to_json(const TestState& state)
7189
}
7290
return j;
7391
}
92+
93+
json::json to_state_test(std::string_view test_name, const state::BlockInfo& block,
94+
state::Transaction& tx, const TestState& pre, evmc_revision rev,
95+
const std::variant<state::TransactionReceipt, std::error_code>& res, const TestState& post)
96+
{
97+
using state::Transaction;
98+
99+
// FIXME: Move to common place.
100+
static constexpr auto SenderSecretKey =
101+
0x00000000000000000000000000000000000000000000000000000002b1263d2b_bytes32;
102+
103+
json::json j;
104+
auto& jt = j[test_name];
105+
106+
auto& jenv = jt["env"];
107+
jenv["currentNumber"] = hex0x(block.number);
108+
jenv["currentTimestamp"] = hex0x(block.timestamp);
109+
jenv["currentGasLimit"] = hex0x(block.gas_limit);
110+
jenv["currentCoinbase"] = hex0x(block.coinbase);
111+
jenv["currentBaseFee"] = hex0x(block.base_fee);
112+
jenv["currentRandom"] = hex0x(block.prev_randao);
113+
114+
jt["pre"] = to_json(pre);
115+
116+
auto& jtx = jt["transaction"];
117+
if (tx.to.has_value())
118+
jtx["to"] = hex0x(*tx.to);
119+
jtx["sender"] = hex0x(tx.sender);
120+
jtx["secretKey"] = hex0x(SenderSecretKey);
121+
jtx["nonce"] = hex0x(tx.nonce);
122+
if (tx.type >= Transaction::Type::eip1559)
123+
{
124+
jtx["maxFeePerGas"] = hex0x(tx.max_gas_price);
125+
jtx["maxPriorityFeePerGas"] = hex0x(tx.max_priority_gas_price);
126+
}
127+
else
128+
{
129+
assert(tx.max_gas_price == tx.max_priority_gas_price);
130+
jtx["gasPrice"] = hex0x(tx.max_gas_price);
131+
}
132+
133+
jtx["data"][0] = hex0x(tx.data);
134+
jtx["gasLimit"][0] = hex0x(tx.gas_limit);
135+
jtx["value"][0] = hex0x(tx.value);
136+
137+
// Force `accessLists` output even if empty.
138+
if (tx.type >= Transaction::Type::access_list)
139+
jtx["accessLists"][0] = json::json::array();
140+
141+
if (!tx.access_list.empty())
142+
{
143+
auto& ja = jtx["accessLists"][0];
144+
for (const auto& [addr, storage_keys] : tx.access_list)
145+
{
146+
json::json je;
147+
je["address"] = hex0x(addr);
148+
auto& jstorage_keys = je["storageKeys"] = json::json::array();
149+
for (const auto& k : storage_keys)
150+
jstorage_keys.emplace_back(hex0x(k));
151+
ja.emplace_back(std::move(je));
152+
}
153+
}
154+
155+
if (tx.type == Transaction::Type::blob)
156+
{
157+
jtx["maxFeePerBlobGas"] = hex0x(tx.max_blob_gas_price);
158+
jtx["blobVersionedHashes"] = json::json::array();
159+
for (const auto& blob_hash : tx.blob_hashes)
160+
{
161+
jtx["blobVersionedHashes"].emplace_back(hex0x(blob_hash));
162+
}
163+
}
164+
165+
if (!tx.authorization_list.empty())
166+
{
167+
auto& ja = jtx["authorizationList"];
168+
for (const auto& [chain_id, addr, nonce, signer, r, s, y_parity] : tx.authorization_list)
169+
{
170+
json::json je;
171+
je["chainId"] = hex0x(chain_id);
172+
je["address"] = hex0x(addr);
173+
je["nonce"] = hex0x(nonce);
174+
je["v"] = hex0x(y_parity);
175+
je["r"] = hex0x(r);
176+
je["s"] = hex0x(s);
177+
if (signer.has_value())
178+
je["signer"] = hex0x(*signer);
179+
ja.emplace_back(std::move(je));
180+
}
181+
}
182+
183+
184+
auto& jpost = jt["post"][to_test_fork_name(rev)][0];
185+
jpost["indexes"] = {{"data", 0}, {"gas", 0}, {"value", 0}};
186+
jpost["hash"] = hex0x(mpt_hash(post));
187+
188+
if (holds_alternative<std::error_code>(res))
189+
{
190+
jpost["expectException"] = get_invalid_tx_message(
191+
static_cast<state::ErrorCode>(std::get<std::error_code>(res).value()));
192+
jpost["logs"] = hex0x(logs_hash(std::vector<state::Log>()));
193+
}
194+
else
195+
{
196+
jpost["logs"] = hex0x(logs_hash(std::get<state::TransactionReceipt>(res).logs));
197+
}
198+
199+
return j;
200+
}
74201
} // namespace evmone::test

test/unittests/state_transition.cpp

+2-113
Original file line numberDiff line numberDiff line change
@@ -150,122 +150,11 @@ void state_transition::TearDown()
150150
export_state_test(res, post);
151151
}
152152

153-
namespace
154-
{
155-
/// Converts EVM revision to the fork name commonly used in tests.
156-
std::string_view to_test_fork_name(evmc_revision rev) noexcept
157-
{
158-
switch (rev)
159-
{
160-
case EVMC_TANGERINE_WHISTLE:
161-
return "EIP150";
162-
case EVMC_SPURIOUS_DRAGON:
163-
return "EIP158";
164-
default:
165-
return evmc::to_string(rev);
166-
}
167-
}
168-
} // namespace
169-
170153
void state_transition::export_state_test(
171154
const std::variant<TransactionReceipt, std::error_code>& res, const TestState& post)
172155
{
173-
json::json j;
174-
auto& jt = j[export_test_name];
175-
176-
auto& jenv = jt["env"];
177-
jenv["currentNumber"] = hex0x(block.number);
178-
jenv["currentTimestamp"] = hex0x(block.timestamp);
179-
jenv["currentGasLimit"] = hex0x(block.gas_limit);
180-
jenv["currentCoinbase"] = hex0x(block.coinbase);
181-
jenv["currentBaseFee"] = hex0x(block.base_fee);
182-
jenv["currentRandom"] = hex0x(block.prev_randao);
183-
184-
jt["pre"] = to_json(pre);
185-
186-
auto& jtx = jt["transaction"];
187-
if (tx.to.has_value())
188-
jtx["to"] = hex0x(*tx.to);
189-
jtx["sender"] = hex0x(tx.sender);
190-
jtx["secretKey"] = hex0x(SenderSecretKey);
191-
jtx["nonce"] = hex0x(tx.nonce);
192-
if (tx.type >= Transaction::Type::eip1559)
193-
{
194-
jtx["maxFeePerGas"] = hex0x(tx.max_gas_price);
195-
jtx["maxPriorityFeePerGas"] = hex0x(tx.max_priority_gas_price);
196-
}
197-
else
198-
{
199-
assert(tx.max_gas_price == tx.max_priority_gas_price);
200-
jtx["gasPrice"] = hex0x(tx.max_gas_price);
201-
}
202-
203-
jtx["data"][0] = hex0x(tx.data);
204-
jtx["gasLimit"][0] = hex0x(tx.gas_limit);
205-
jtx["value"][0] = hex0x(tx.value);
206-
207-
// Force `accessLists` output even if empty.
208-
if (tx.type >= Transaction::Type::access_list)
209-
jtx["accessLists"][0] = json::json::array();
210-
211-
if (!tx.access_list.empty())
212-
{
213-
auto& ja = jtx["accessLists"][0];
214-
for (const auto& [addr, storage_keys] : tx.access_list)
215-
{
216-
json::json je;
217-
je["address"] = hex0x(addr);
218-
auto& jstorage_keys = je["storageKeys"] = json::json::array();
219-
for (const auto& k : storage_keys)
220-
jstorage_keys.emplace_back(hex0x(k));
221-
ja.emplace_back(std::move(je));
222-
}
223-
}
224-
225-
if (tx.type == Transaction::Type::blob)
226-
{
227-
jtx["maxFeePerBlobGas"] = hex0x(tx.max_blob_gas_price);
228-
jtx["blobVersionedHashes"] = json::json::array();
229-
for (const auto& blob_hash : tx.blob_hashes)
230-
{
231-
jtx["blobVersionedHashes"].emplace_back(hex0x(blob_hash));
232-
}
233-
}
234-
235-
if (!tx.authorization_list.empty())
236-
{
237-
auto& ja = jtx["authorizationList"];
238-
for (const auto& [chain_id, addr, nonce, signer, r, s, y_parity] : tx.authorization_list)
239-
{
240-
json::json je;
241-
je["chainId"] = hex0x(chain_id);
242-
je["address"] = hex0x(addr);
243-
je["nonce"] = hex0x(nonce);
244-
je["v"] = hex0x(y_parity);
245-
je["r"] = hex0x(r);
246-
je["s"] = hex0x(s);
247-
if (signer.has_value())
248-
je["signer"] = hex0x(*signer);
249-
ja.emplace_back(std::move(je));
250-
}
251-
}
252-
253-
254-
auto& jpost = jt["post"][to_test_fork_name(rev)][0];
255-
jpost["indexes"] = {{"data", 0}, {"gas", 0}, {"value", 0}};
256-
jpost["hash"] = hex0x(mpt_hash(post));
257-
258-
if (holds_alternative<std::error_code>(res))
259-
{
260-
jpost["expectException"] =
261-
get_invalid_tx_message(static_cast<ErrorCode>(std::get<std::error_code>(res).value()));
262-
jpost["logs"] = hex0x(logs_hash(std::vector<Log>()));
263-
}
264-
else
265-
{
266-
jpost["logs"] = hex0x(logs_hash(std::get<TransactionReceipt>(res).logs));
267-
}
268-
156+
const auto j = to_state_test(
157+
export_test_name, block, tx, pre, rev, res, post);
269158
std::ofstream{export_file_path} << std::setw(2) << j;
270159
}
271160
} // namespace evmone::test

0 commit comments

Comments
 (0)