|
3 | 3 | // SPDX-License-Identifier: Apache-2.0
|
4 | 4 |
|
5 | 5 | #include "statetest.hpp"
|
| 6 | +#include <test/state/mpt_hash.hpp> |
6 | 7 |
|
7 | 8 | namespace evmone::test
|
8 | 9 | {
|
| 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 | + |
9 | 27 | [[nodiscard]] std::string get_invalid_tx_message(state::ErrorCode errc) noexcept
|
10 | 28 | {
|
11 | 29 | using namespace state;
|
@@ -71,4 +89,113 @@ json::json to_json(const TestState& state)
|
71 | 89 | }
|
72 | 90 | return j;
|
73 | 91 | }
|
| 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 | +} |
74 | 201 | } // namespace evmone::test
|
0 commit comments