LCOV - differential code coverage report
Current view: top level - test/t8n - t8n.cpp (source / functions) Coverage Total Hit UBC CBC
Current: DIFF_COVERAGE Lines: 82.9 % 152 126 26 126
Current Date: 2024-03-20 16:29:22 Functions: 100.0 % 1 1 1
Baseline: coverage_BASE.lcov
Baseline Date: 2024-03-20 14:19:08

           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 "../state/errors.hpp"
       6                 : #include "../state/ethash_difficulty.hpp"
       7                 : #include "../state/mpt_hash.hpp"
       8                 : #include "../state/rlp.hpp"
       9                 : #include "../statetest/statetest.hpp"
      10                 : #include "../utils/utils.hpp"
      11                 : #include <evmone/evmone.h>
      12                 : #include <evmone/version.h>
      13                 : #include <nlohmann/json.hpp>
      14                 : #include <filesystem>
      15                 : #include <fstream>
      16                 : #include <iostream>
      17                 : #include <string_view>
      18                 : 
      19                 : namespace fs = std::filesystem;
      20                 : namespace json = nlohmann;
      21                 : using namespace evmone;
      22                 : using namespace evmone::test;
      23                 : using namespace std::literals;
      24                 : 
      25 CBC          54 : int main(int argc, const char* argv[])
      26                 : {
      27              54 :     evmc_revision rev = {};
      28              54 :     fs::path alloc_file;
      29              54 :     fs::path env_file;
      30              54 :     fs::path txs_file;
      31              54 :     fs::path output_dir;
      32              54 :     fs::path output_result_file;
      33              54 :     fs::path output_alloc_file;
      34              54 :     fs::path output_body_file;
      35              54 :     std::optional<uint64_t> block_reward;
      36              54 :     uint64_t chain_id = 0;
      37              54 :     bool trace = false;
      38                 : 
      39                 :     try
      40                 :     {
      41             691 :         for (int i = 0; i < argc; ++i)
      42                 :         {
      43             638 :             const std::string_view arg{argv[i]};
      44                 : 
      45             638 :             if (arg == "-v")
      46                 :             {
      47               1 :                 std::cout << "evmone-t8n " EVMONE_VERSION "\n";
      48               1 :                 return 0;
      49                 :             }
      50             637 :             if (arg == "--state.fork" && ++i < argc)
      51              53 :                 rev = to_rev(argv[i]);
      52             584 :             else if (arg == "--input.alloc" && ++i < argc)
      53              53 :                 alloc_file = argv[i];
      54             531 :             else if (arg == "--input.env" && ++i < argc)
      55              53 :                 env_file = argv[i];
      56             478 :             else if (arg == "--input.txs" && ++i < argc)
      57              53 :                 txs_file = argv[i];
      58             425 :             else if (arg == "--output.basedir" && ++i < argc)
      59              53 :                 output_dir = argv[i];
      60             372 :             else if (arg == "--output.result" && ++i < argc)
      61              53 :                 output_result_file = argv[i];
      62             319 :             else if (arg == "--output.alloc" && ++i < argc)
      63              53 :                 output_alloc_file = argv[i];
      64             266 :             else if (arg == "--state.reward" && ++i < argc && argv[i] != "-1"sv)
      65              53 :                 block_reward = intx::from_string<uint64_t>(argv[i]);
      66             213 :             else if (arg == "--state.chainid" && ++i < argc)
      67              53 :                 chain_id = intx::from_string<uint64_t>(argv[i]);
      68             160 :             else if (arg == "--output.body" && ++i < argc)
      69 UBC           0 :                 output_body_file = argv[i];
      70 CBC         160 :             else if (arg == "--trace")
      71 UBC           0 :                 trace = true;
      72                 :         }
      73                 : 
      74 CBC          53 :         state::BlockInfo block;
      75              53 :         state::State state;
      76                 : 
      77              53 :         if (!alloc_file.empty())
      78                 :         {
      79             106 :             const auto j = json::json::parse(std::ifstream{alloc_file}, nullptr, false);
      80              53 :             state = test::from_json<state::State>(j);
      81              53 :         }
      82              53 :         if (!env_file.empty())
      83                 :         {
      84             106 :             const auto j = json::json::parse(std::ifstream{env_file});
      85              53 :             block = test::from_json<state::BlockInfo>(j);
      86              53 :         }
      87                 : 
      88              53 :         json::json j_result;
      89                 : 
      90                 :         // Difficulty was received from upstream. No need to calc
      91                 :         // TODO: Check if it's needed by the blockchain test. If not remove if statement true branch
      92              53 :         if (block.difficulty != 0)
      93 UBC           0 :             j_result["currentDifficulty"] = hex0x(block.difficulty);
      94                 :         else
      95                 :         {
      96 CBC          53 :             const auto current_difficulty = state::calculate_difficulty(block.parent_difficulty,
      97              53 :                 block.parent_ommers_hash != EmptyListHash, block.parent_timestamp, block.timestamp,
      98                 :                 block.number, rev);
      99                 : 
     100              53 :             j_result["currentDifficulty"] = hex0x(current_difficulty);
     101              53 :             block.difficulty = current_difficulty;
     102                 : 
     103              53 :             if (rev < EVMC_PARIS)  // Override prev_randao with difficulty pre-Merge
     104 UBC           0 :                 block.prev_randao = intx::be::store<bytes32>(intx::uint256{current_difficulty});
     105                 :         }
     106                 : 
     107 CBC          53 :         j_result["currentBaseFee"] = hex0x(block.base_fee);
     108                 : 
     109              53 :         int64_t cumulative_gas_used = 0;
     110              53 :         int64_t blob_gas_left = state::BlockInfo::MAX_BLOB_GAS_PER_BLOCK;
     111              53 :         std::vector<state::Transaction> transactions;
     112              53 :         std::vector<state::TransactionReceipt> receipts;
     113              53 :         int64_t block_gas_left = block.gas_limit;
     114                 : 
     115              53 :         validate_state(state, rev);
     116                 : 
     117                 :         // Parse and execute transactions
     118              53 :         if (!txs_file.empty())
     119                 :         {
     120             106 :             const auto j_txs = json::json::parse(std::ifstream{txs_file});
     121                 : 
     122              53 :             evmc::VM vm{evmc_create_evmone()};
     123                 : 
     124              53 :             if (trace)
     125 UBC           0 :                 vm.set_option("trace", "1");
     126                 : 
     127 CBC          53 :             std::vector<state::Log> txs_logs;
     128                 : 
     129              53 :             if (j_txs.is_array())
     130                 :             {
     131              53 :                 j_result["receipts"] = json::json::array();
     132              53 :                 j_result["rejected"] = json::json::array();
     133                 : 
     134             106 :                 for (size_t i = 0; i < j_txs.size(); ++i)
     135                 :                 {
     136              53 :                     auto tx = test::from_json<state::Transaction>(j_txs[i]);
     137              53 :                     tx.chain_id = chain_id;
     138                 : 
     139              53 :                     const auto computed_tx_hash = keccak256(rlp::encode(tx));
     140              53 :                     const auto computed_tx_hash_str = hex0x(computed_tx_hash);
     141                 : 
     142              53 :                     if (j_txs[i].contains("hash"))
     143                 :                     {
     144                 :                         const auto loaded_tx_hash_opt =
     145              53 :                             evmc::from_hex<bytes32>(j_txs[i]["hash"].get<std::string>());
     146                 : 
     147              53 :                         if (loaded_tx_hash_opt != computed_tx_hash)
     148 UBC           0 :                             throw std::logic_error("transaction hash mismatched: computed " +
     149               0 :                                                    computed_tx_hash_str + ", expected " +
     150               0 :                                                    hex0x(loaded_tx_hash_opt.value()));
     151                 :                     }
     152                 : 
     153 CBC          53 :                     std::ofstream trace_file_output;
     154              53 :                     const auto orig_clog_buf = std::clog.rdbuf();
     155              53 :                     if (trace)
     156                 :                     {
     157                 :                         const auto output_filename =
     158                 :                             output_dir /
     159 UBC           0 :                             ("trace-" + std::to_string(i) + "-" + computed_tx_hash_str + ".jsonl");
     160                 : 
     161                 :                         // `trace` flag enables trace logging to std::clog.
     162                 :                         // Redirect std::clog to the output file.
     163               0 :                         trace_file_output.open(output_filename);
     164               0 :                         std::clog.rdbuf(trace_file_output.rdbuf());
     165               0 :                     }
     166                 : 
     167                 :                     auto res =
     168 CBC          53 :                         state::transition(state, block, tx, rev, vm, block_gas_left, blob_gas_left);
     169                 : 
     170              53 :                     if (holds_alternative<std::error_code>(res))
     171                 :                     {
     172 UBC           0 :                         const auto ec = std::get<std::error_code>(res);
     173               0 :                         json::json j_rejected_tx;
     174               0 :                         j_rejected_tx["hash"] = computed_tx_hash_str;
     175               0 :                         j_rejected_tx["index"] = i;
     176               0 :                         j_rejected_tx["error"] = ec.message();
     177               0 :                         j_result["rejected"].push_back(j_rejected_tx);
     178               0 :                     }
     179                 :                     else
     180                 :                     {
     181 CBC          53 :                         auto& receipt = get<state::TransactionReceipt>(res);
     182                 : 
     183              53 :                         const auto& tx_logs = receipt.logs;
     184                 : 
     185              53 :                         txs_logs.insert(txs_logs.end(), tx_logs.begin(), tx_logs.end());
     186              53 :                         auto& j_receipt = j_result["receipts"][j_result["receipts"].size()];
     187                 : 
     188              53 :                         j_receipt["transactionHash"] = computed_tx_hash_str;
     189              53 :                         j_receipt["gasUsed"] = hex0x(static_cast<uint64_t>(receipt.gas_used));
     190              53 :                         cumulative_gas_used += receipt.gas_used;
     191              53 :                         receipt.cumulative_gas_used = cumulative_gas_used;
     192              53 :                         if (rev < EVMC_BYZANTIUM)
     193 UBC           0 :                             receipt.post_state = state::mpt_hash(state.get_accounts());
     194 CBC          53 :                         j_receipt["cumulativeGasUsed"] = hex0x(cumulative_gas_used);
     195                 : 
     196              53 :                         j_receipt["blockHash"] = hex0x(bytes32{});
     197              53 :                         j_receipt["contractAddress"] = hex0x(address{});
     198              53 :                         j_receipt["logsBloom"] = hex0x(receipt.logs_bloom_filter);
     199              53 :                         j_receipt["logs"] = json::json::array();  // FIXME: Add to_json<state:Log>
     200              53 :                         j_receipt["root"] = "";
     201              53 :                         j_receipt["status"] = "0x1";
     202              53 :                         j_receipt["transactionIndex"] = hex0x(i);
     203              53 :                         blob_gas_left -= tx.blob_gas_used();
     204              53 :                         transactions.emplace_back(std::move(tx));
     205              53 :                         block_gas_left -= receipt.gas_used;
     206              53 :                         receipts.emplace_back(std::move(receipt));
     207                 :                     }
     208                 : 
     209                 :                     // Restore original std::clog buffer (otherwise std::clog crashes at exit).
     210              53 :                     if (trace)
     211 UBC           0 :                         std::clog.rdbuf(orig_clog_buf);
     212 CBC          53 :                 }
     213                 :             }
     214                 : 
     215              53 :             state::finalize(
     216                 :                 state, rev, block.coinbase, block_reward, block.ommers, block.withdrawals);
     217                 : 
     218              53 :             j_result["logsHash"] = hex0x(logs_hash(txs_logs));
     219              53 :             j_result["stateRoot"] = hex0x(state::mpt_hash(state.get_accounts()));
     220              53 :         }
     221                 : 
     222              53 :         j_result["logsBloom"] = hex0x(compute_bloom_filter(receipts));
     223              53 :         j_result["receiptsRoot"] = hex0x(state::mpt_hash(receipts));
     224              53 :         if (rev >= EVMC_SHANGHAI)
     225              53 :             j_result["withdrawalsRoot"] = hex0x(state::mpt_hash(block.withdrawals));
     226                 : 
     227              53 :         j_result["txRoot"] = hex0x(state::mpt_hash(transactions));
     228              53 :         j_result["gasUsed"] = hex0x(cumulative_gas_used);
     229              53 :         if (rev >= EVMC_CANCUN)
     230                 :         {
     231              53 :             j_result["blobGasUsed"] =
     232             106 :                 hex0x(state::BlockInfo::MAX_BLOB_GAS_PER_BLOCK - blob_gas_left);
     233              53 :             j_result["currentExcessBlobGas"] = hex0x(block.excess_blob_gas);
     234                 :         }
     235                 : 
     236              53 :         std::ofstream{output_dir / output_result_file} << std::setw(2) << j_result;
     237                 : 
     238                 :         // Print out current state to outAlloc file
     239             106 :         std::ofstream{output_dir / output_alloc_file} << std::setw(2)
     240              53 :                                                       << to_json(state.get_accounts());
     241                 : 
     242              53 :         if (!output_body_file.empty())
     243 UBC           0 :             std::ofstream{output_dir / output_body_file} << hex0x(rlp::encode(transactions));
     244 CBC          53 :     }
     245 UBC           0 :     catch (const std::exception& e)
     246                 :     {
     247               0 :         std::cerr << e.what() << '\n';
     248               0 :         return 1;
     249               0 :     }
     250                 : 
     251 CBC          53 :     return 0;
     252              54 : }
        

Generated by: LCOV version 2.0-1