TLA Line data Source code
1 : // evmone: Fast Ethereum Virtual Machine implementation
2 : // Copyright 2023 The evmone Authors.
3 : // SPDX-License-Identifier: Apache-2.0
4 :
5 : #include "../statetest/statetest.hpp"
6 : #include "../utils/utils.hpp"
7 : #include "blockchaintest.hpp"
8 :
9 : namespace evmone::test
10 : {
11 :
12 : namespace
13 : {
14 : template <typename T>
15 UBC 0 : T load_if_exists(const json::json& j, std::string_view key)
16 : {
17 0 : if (const auto it = j.find(key); it != j.end())
18 0 : return from_json<T>(*it);
19 0 : return {};
20 : }
21 : } // namespace
22 :
23 : template <>
24 0 : BlockHeader from_json<BlockHeader>(const json::json& j)
25 : {
26 : return {
27 0 : .parent_hash = from_json<hash256>(j.at("parentHash")),
28 0 : .coinbase = from_json<address>(j.at("coinbase")),
29 0 : .state_root = from_json<hash256>(j.at("stateRoot")),
30 0 : .receipts_root = from_json<hash256>(j.at("receiptTrie")),
31 0 : .logs_bloom = state::bloom_filter_from_bytes(from_json<bytes>(j.at("bloom"))),
32 0 : .difficulty = load_if_exists<int64_t>(j, "difficulty"),
33 0 : .prev_randao = load_if_exists<bytes32>(j, "mixHash"),
34 0 : .block_number = from_json<int64_t>(j.at("number")),
35 0 : .gas_limit = from_json<int64_t>(j.at("gasLimit")),
36 0 : .gas_used = from_json<int64_t>(j.at("gasUsed")),
37 0 : .timestamp = from_json<int64_t>(j.at("timestamp")),
38 0 : .extra_data = from_json<bytes>(j.at("extraData")),
39 0 : .base_fee_per_gas = load_if_exists<uint64_t>(j, "baseFeePerGas"),
40 0 : .hash = from_json<hash256>(j.at("hash")),
41 0 : .transactions_root = from_json<hash256>(j.at("transactionsTrie")),
42 0 : .withdrawal_root = load_if_exists<hash256>(j, "withdrawalsRoot"),
43 0 : .parent_beacon_block_root = load_if_exists<hash256>(j, "parentBeaconBlockRoot"),
44 0 : .excess_blob_gas = load_if_exists<uint64_t>(j, "excessBlobGas"),
45 0 : };
46 : }
47 :
48 0 : static TestBlock load_test_block(const json::json& j, evmc_revision rev)
49 : {
50 : using namespace state;
51 0 : TestBlock tb;
52 :
53 0 : if (const auto it = j.find("blockHeader"); it != j.end())
54 : {
55 0 : tb.expected_block_header = from_json<BlockHeader>(*it);
56 0 : tb.block_info.number = tb.expected_block_header.block_number;
57 0 : tb.block_info.timestamp = tb.expected_block_header.timestamp;
58 0 : tb.block_info.gas_limit = tb.expected_block_header.gas_limit;
59 0 : tb.block_info.coinbase = tb.expected_block_header.coinbase;
60 0 : tb.block_info.difficulty = tb.expected_block_header.difficulty;
61 0 : tb.block_info.prev_randao = tb.expected_block_header.prev_randao;
62 0 : tb.block_info.base_fee = tb.expected_block_header.base_fee_per_gas;
63 0 : tb.block_info.parent_beacon_block_root = tb.expected_block_header.parent_beacon_block_root;
64 : tb.block_info.blob_base_fee =
65 0 : compute_blob_gas_price(tb.expected_block_header.excess_blob_gas);
66 :
67 : // Override prev_randao with difficulty pre-Merge
68 0 : if (rev < EVMC_PARIS)
69 : {
70 : tb.block_info.prev_randao =
71 0 : intx::be::store<bytes32>(intx::uint256{tb.block_info.difficulty});
72 : }
73 : }
74 :
75 0 : if (const auto it = j.find("expectException"); it != j.end())
76 : {
77 : // TODO: Add support for invalid blocks.
78 0 : throw UnsupportedTestFeature("tests with invalid blocks are not supported");
79 : }
80 :
81 0 : if (const auto it = j.find("transactionSequence"); it != j.end())
82 : {
83 : // TODO: Add support for invalid blocks.
84 0 : throw UnsupportedTestFeature("tests with invalid transactions are not supported");
85 : }
86 :
87 0 : if (const auto it = j.find("uncleHeaders"); it != j.end())
88 : {
89 0 : const auto current_block_number = tb.block_info.number;
90 0 : for (const auto& ommer : *it)
91 : {
92 0 : tb.block_info.ommers.push_back({from_json<address>(ommer.at("coinbase")),
93 : static_cast<uint32_t>(
94 0 : current_block_number - from_json<int64_t>(ommer.at("number")))});
95 : }
96 : }
97 :
98 0 : if (auto it = j.find("withdrawals"); it != j.end())
99 : {
100 0 : for (const auto& withdrawal : *it)
101 0 : tb.block_info.withdrawals.emplace_back(from_json<Withdrawal>(withdrawal));
102 : }
103 :
104 0 : if (auto it = j.find("transactions"); it != j.end())
105 : {
106 0 : for (const auto& tx : *it)
107 0 : tb.transactions.emplace_back(from_json<Transaction>(tx));
108 : }
109 :
110 0 : return tb;
111 0 : }
112 :
113 : namespace
114 : {
115 0 : BlockchainTest load_blockchain_test_case(const std::string& name, const json::json& j)
116 : {
117 : using namespace state;
118 :
119 0 : BlockchainTest bt;
120 0 : bt.name = name;
121 0 : bt.genesis_block_header = from_json<BlockHeader>(j.at("genesisBlockHeader"));
122 0 : bt.pre_state = from_json<State>(j.at("pre"));
123 0 : bt.rev = to_rev_schedule(j.at("network").get<std::string>());
124 :
125 0 : for (const auto& el : j.at("blocks"))
126 0 : bt.test_blocks.emplace_back(load_test_block(el, bt.rev.get_revision(0)));
127 :
128 0 : bt.expectation.last_block_hash = from_json<hash256>(j.at("lastblockhash"));
129 :
130 0 : if (const auto it = j.find("postState"); it != j.end())
131 0 : bt.expectation.post_state = from_json<State>(*it);
132 0 : else if (const auto it_hash = j.find("postStateHash"); it_hash != j.end())
133 0 : bt.expectation.post_state = from_json<hash256>(*it_hash);
134 :
135 0 : return bt;
136 0 : }
137 : } // namespace
138 :
139 0 : static void from_json(const json::json& j, std::vector<BlockchainTest>& o)
140 : {
141 0 : for (const auto& elem_it : j.items())
142 0 : o.emplace_back(load_blockchain_test_case(elem_it.key(), elem_it.value()));
143 0 : }
144 :
145 0 : std::vector<BlockchainTest> load_blockchain_tests(std::istream& input)
146 : {
147 0 : return json::json::parse(input).get<std::vector<BlockchainTest>>();
148 : }
149 :
150 : } // namespace evmone::test
|