LCOV - differential code coverage report
Current view: top level - test/state - state.cpp (source / functions) Coverage Total Hit UBC GBC CBC
Current: DIFF_COVERAGE Lines: 61.6 % 289 178 111 1 177
Current Date: 2024-03-20 16:29:22 Functions: 60.0 % 40 24 16 24
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 2022 The evmone Authors.
       3                 : // SPDX-License-Identifier: Apache-2.0
       4                 : 
       5                 : #include "state.hpp"
       6                 : #include "../utils/stdx/utility.hpp"
       7                 : #include "errors.hpp"
       8                 : #include "host.hpp"
       9                 : #include "rlp.hpp"
      10                 : #include <evmone/evmone.h>
      11                 : #include <evmone/execution_state.hpp>
      12                 : 
      13                 : namespace evmone::state
      14                 : {
      15                 : namespace
      16                 : {
      17 UBC           0 : inline constexpr int64_t num_words(size_t size_in_bytes) noexcept
      18                 : {
      19               0 :     return static_cast<int64_t>((size_in_bytes + 31) / 32);
      20                 : }
      21                 : 
      22 CBC          53 : int64_t compute_tx_data_cost(evmc_revision rev, bytes_view data) noexcept
      23                 : {
      24              53 :     constexpr int64_t zero_byte_cost = 4;
      25              53 :     const int64_t nonzero_byte_cost = rev >= EVMC_ISTANBUL ? 16 : 68;
      26              53 :     int64_t cost = 0;
      27            1589 :     for (const auto b : data)
      28            1536 :         cost += (b == 0) ? zero_byte_cost : nonzero_byte_cost;
      29              53 :     return cost;
      30                 : }
      31                 : 
      32              53 : int64_t compute_access_list_cost(const AccessList& access_list) noexcept
      33                 : {
      34                 :     static constexpr auto storage_key_cost = 1900;
      35                 :     static constexpr auto address_cost = 2400;
      36                 : 
      37              53 :     int64_t cost = 0;
      38              53 :     for (const auto& a : access_list)
      39 UBC           0 :         cost += address_cost + static_cast<int64_t>(a.second.size()) * storage_key_cost;
      40 CBC          53 :     return cost;
      41                 : }
      42                 : 
      43              53 : int64_t compute_tx_intrinsic_cost(evmc_revision rev, const Transaction& tx) noexcept
      44                 : {
      45                 :     static constexpr auto call_tx_cost = 21000;
      46                 :     static constexpr auto create_tx_cost = 53000;
      47                 :     static constexpr auto initcode_word_cost = 2;
      48              53 :     const auto is_create = !tx.to.has_value();
      49                 :     const auto initcode_cost =
      50              53 :         is_create && rev >= EVMC_SHANGHAI ? initcode_word_cost * num_words(tx.data.size()) : 0;
      51              53 :     const auto tx_cost = is_create && rev >= EVMC_HOMESTEAD ? create_tx_cost : call_tx_cost;
      52              53 :     return tx_cost + compute_tx_data_cost(rev, tx.data) + compute_access_list_cost(tx.access_list) +
      53              53 :            initcode_cost;
      54                 : }
      55                 : 
      56              53 : evmc_message build_message(const Transaction& tx, int64_t execution_gas_limit) noexcept
      57                 : {
      58              53 :     const auto recipient = tx.to.has_value() ? *tx.to : evmc::address{};
      59                 :     return {
      60              53 :         tx.to.has_value() ? EVMC_CALL : EVMC_CREATE,
      61                 :         0,
      62                 :         0,
      63                 :         execution_gas_limit,
      64                 :         recipient,
      65                 :         tx.sender,
      66              53 :         tx.data.data(),
      67              53 :         tx.data.size(),
      68             106 :         intx::be::store<evmc::uint256be>(tx.value),
      69                 :         {},
      70                 :         recipient,
      71             106 :     };
      72                 : }
      73                 : }  // namespace
      74                 : 
      75             212 : Account& State::insert(const address& addr, Account account)
      76                 : {
      77             212 :     const auto r = m_accounts.insert({addr, std::move(account)});
      78             212 :     assert(r.second);
      79             212 :     return r.first->second;
      80                 : }
      81                 : 
      82            1543 : Account* State::find(const address& addr) noexcept
      83                 : {
      84            1543 :     const auto it = m_accounts.find(addr);
      85            1543 :     if (it != m_accounts.end())
      86            1456 :         return &it->second;
      87              87 :     return nullptr;
      88                 : }
      89                 : 
      90            1008 : Account& State::get(const address& addr) noexcept
      91                 : {
      92            1008 :     auto acc = find(addr);
      93            1008 :     assert(acc != nullptr);
      94            1008 :     return *acc;
      95                 : }
      96                 : 
      97             343 : Account& State::get_or_insert(const address& addr, Account account)
      98                 : {
      99             343 :     if (const auto acc = find(addr); acc != nullptr)
     100             290 :         return *acc;
     101              53 :     return insert(addr, std::move(account));
     102                 : }
     103                 : 
     104             185 : Account& State::touch(const address& addr)
     105                 : {
     106             185 :     auto& acc = get_or_insert(addr, {.erase_if_empty = true});
     107             185 :     if (!acc.erase_if_empty && acc.is_empty())
     108                 :     {
     109 UBC           0 :         acc.erase_if_empty = true;
     110               0 :         m_journal.emplace_back(JournalTouched{addr});
     111                 :     }
     112 CBC         185 :     return acc;
     113                 : }
     114                 : 
     115 UBC           0 : void State::journal_balance_change(const address& addr, const intx::uint256& prev_balance)
     116                 : {
     117               0 :     m_journal.emplace_back(JournalBalanceChange{{addr}, prev_balance});
     118               0 : }
     119                 : 
     120 CBC         288 : void State::journal_storage_change(
     121                 :     const address& addr, const bytes32& key, const StorageValue& value)
     122                 : {
     123             288 :     m_journal.emplace_back(JournalStorageChange{{addr}, key, value.current, value.access_status});
     124             288 : }
     125                 : 
     126             153 : void State::journal_transient_storage_change(
     127                 :     const address& addr, const bytes32& key, const bytes32& value)
     128                 : {
     129             153 :     m_journal.emplace_back(JournalTransientStorageChange{{addr}, key, value});
     130             153 : }
     131                 : 
     132 UBC           0 : void State::journal_bump_nonce(const address& addr)
     133                 : {
     134               0 :     m_journal.emplace_back(JournalNonceBump{addr});
     135               0 : }
     136                 : 
     137               0 : void State::journal_create(const address& addr, bool existed)
     138                 : {
     139               0 :     m_journal.emplace_back(JournalCreate{{addr}, existed});
     140               0 : }
     141                 : 
     142               0 : void State::journal_destruct(const address& addr)
     143                 : {
     144               0 :     m_journal.emplace_back(JournalDestruct{addr});
     145               0 : }
     146                 : 
     147 CBC         134 : void State::journal_access_account(const address& addr)
     148                 : {
     149             134 :     m_journal.emplace_back(JournalAccessAccount{addr});
     150             134 : }
     151                 : 
     152              34 : void State::rollback(size_t checkpoint)
     153                 : {
     154              82 :     while (m_journal.size() != checkpoint)
     155                 :     {
     156              48 :         std::visit(
     157              48 :             [this](const auto& e) {
     158                 :                 using T = std::decay_t<decltype(e)>;
     159                 :                 if constexpr (std::is_same_v<T, JournalNonceBump>)
     160                 :                 {
     161 UBC           0 :                     get(e.addr).nonce -= 1;
     162                 :                 }
     163                 :                 else if constexpr (std::is_same_v<T, JournalTouched>)
     164                 :                 {
     165               0 :                     get(e.addr).erase_if_empty = false;
     166                 :                 }
     167                 :                 else if constexpr (std::is_same_v<T, JournalDestruct>)
     168                 :                 {
     169               0 :                     get(e.addr).destructed = false;
     170                 :                 }
     171                 :                 else if constexpr (std::is_same_v<T, JournalAccessAccount>)
     172                 :                 {
     173               0 :                     get(e.addr).access_status = EVMC_ACCESS_COLD;
     174                 :                 }
     175                 :                 else if constexpr (std::is_same_v<T, JournalCreate>)
     176                 :                 {
     177               0 :                     if (e.existed)
     178                 :                     {
     179                 :                         // This account is not always "touched". TODO: Why?
     180               0 :                         auto& a = get(e.addr);
     181               0 :                         a.nonce = 0;
     182               0 :                         a.code.clear();
     183                 :                     }
     184                 :                     else
     185                 :                     {
     186                 :                         // TODO: Before Spurious Dragon we don't clear empty accounts ("erasable")
     187                 :                         //       so we need to delete them here explicitly.
     188                 :                         //       This should be changed by tuning "erasable" flag
     189                 :                         //       and clear in all revisions.
     190               0 :                         m_accounts.erase(e.addr);
     191                 :                     }
     192                 :                 }
     193                 :                 else if constexpr (std::is_same_v<T, JournalStorageChange>)
     194                 :                 {
     195               0 :                     auto& s = get(e.addr).storage.find(e.key)->second;
     196               0 :                     s.current = e.prev_value;
     197               0 :                     s.access_status = e.prev_access_status;
     198                 :                 }
     199                 :                 else if constexpr (std::is_same_v<T, JournalTransientStorageChange>)
     200                 :                 {
     201 CBC          48 :                     auto& s = get(e.addr).transient_storage.find(e.key)->second;
     202              48 :                     s = e.prev_value;
     203                 :                 }
     204                 :                 else if constexpr (std::is_same_v<T, JournalBalanceChange>)
     205                 :                 {
     206 UBC           0 :                     get(e.addr).balance = e.prev_balance;
     207                 :                 }
     208                 :                 else
     209                 :                 {
     210                 :                     // TODO(C++23): Change condition to `false` once CWG2518 is in.
     211                 :                     static_assert(std::is_void_v<T>, "unhandled journal entry type");
     212                 :                 }
     213 CBC          48 :             },
     214              48 :             m_journal.back());
     215              48 :         m_journal.pop_back();
     216                 :     }
     217              34 : }
     218                 : 
     219              53 : intx::uint256 compute_blob_gas_price(uint64_t excess_blob_gas) noexcept
     220                 : {
     221                 :     /// A helper function approximating `factor * e ** (numerator / denominator)`.
     222                 :     /// https://eips.ethereum.org/EIPS/eip-4844#helpers
     223              53 :     static constexpr auto fake_exponential = [](uint64_t factor, uint64_t numerator,
     224                 :                                                  uint64_t denominator) noexcept {
     225              53 :         intx::uint256 i = 1;
     226              53 :         intx::uint256 output = 0;
     227              53 :         intx::uint256 numerator_accum = factor * denominator;
     228             106 :         while (numerator_accum > 0)
     229                 :         {
     230              53 :             output += numerator_accum;
     231              53 :             numerator_accum = (numerator_accum * numerator) / (denominator * i);
     232              53 :             i += 1;
     233                 :         }
     234              53 :         return output / denominator;
     235                 :     };
     236                 : 
     237                 :     static constexpr auto MIN_BLOB_GASPRICE = 1;
     238                 :     static constexpr auto BLOB_GASPRICE_UPDATE_FRACTION = 3338477;
     239              53 :     return fake_exponential(MIN_BLOB_GASPRICE, excess_blob_gas, BLOB_GASPRICE_UPDATE_FRACTION);
     240                 : }
     241                 : 
     242                 : /// Validates transaction and computes its execution gas limit (the amount of gas provided to EVM).
     243                 : /// @return  Execution gas limit or transaction validation error.
     244              53 : std::variant<int64_t, std::error_code> validate_transaction(const Account& sender_acc,
     245                 :     const BlockInfo& block, const Transaction& tx, evmc_revision rev, int64_t block_gas_left,
     246                 :     int64_t blob_gas_left) noexcept
     247                 : {
     248              53 :     switch (tx.type)
     249                 :     {
     250 UBC           0 :     case Transaction::Type::blob:
     251               0 :         if (rev < EVMC_CANCUN)
     252               0 :             return make_error_code(TX_TYPE_NOT_SUPPORTED);
     253               0 :         if (!tx.to.has_value())
     254               0 :             return make_error_code(CREATE_BLOB_TX);
     255               0 :         if (tx.blob_hashes.empty())
     256               0 :             return make_error_code(EMPTY_BLOB_HASHES_LIST);
     257                 : 
     258               0 :         if (tx.max_blob_gas_price < block.blob_base_fee)
     259               0 :             return make_error_code(FEE_CAP_LESS_THEN_BLOCKS);
     260                 : 
     261               0 :         if (std::ranges::any_of(tx.blob_hashes, [](const auto& h) { return h.bytes[0] != 0x01; }))
     262               0 :             return make_error_code(INVALID_BLOB_HASH_VERSION);
     263               0 :         if (std::cmp_greater(tx.blob_gas_used(), blob_gas_left))
     264               0 :             return make_error_code(BLOB_GAS_LIMIT_EXCEEDED);
     265                 :         [[fallthrough]];
     266                 : 
     267                 :     case Transaction::Type::eip1559:
     268 CBC           1 :         if (rev < EVMC_LONDON)
     269 UBC           0 :             return make_error_code(TX_TYPE_NOT_SUPPORTED);
     270                 : 
     271 CBC           1 :         if (tx.max_priority_gas_price > tx.max_gas_price)
     272 UBC           0 :             return make_error_code(TIP_GT_FEE_CAP);  // Priority gas price is too high.
     273                 :         [[fallthrough]];
     274                 : 
     275                 :     case Transaction::Type::access_list:
     276 CBC           1 :         if (rev < EVMC_BERLIN)
     277 UBC           0 :             return make_error_code(TX_TYPE_NOT_SUPPORTED);
     278                 :         [[fallthrough]];
     279                 : 
     280                 :     case Transaction::Type::legacy:;
     281                 :     }
     282                 : 
     283 CBC          53 :     assert(tx.max_priority_gas_price <= tx.max_gas_price);
     284                 : 
     285              53 :     if (tx.gas_limit > block_gas_left)
     286 UBC           0 :         return make_error_code(GAS_LIMIT_REACHED);
     287                 : 
     288 CBC          53 :     if (tx.max_gas_price < block.base_fee)
     289 UBC           0 :         return make_error_code(FEE_CAP_LESS_THEN_BLOCKS);
     290                 : 
     291 CBC          53 :     if (!sender_acc.code.empty())
     292 UBC           0 :         return make_error_code(SENDER_NOT_EOA);  // Origin must not be a contract (EIP-3607).
     293                 : 
     294 CBC          53 :     if (sender_acc.nonce == Account::NonceMax)  // Nonce value limit (EIP-2681).
     295 UBC           0 :         return make_error_code(NONCE_HAS_MAX_VALUE);
     296                 : 
     297 CBC          53 :     if (sender_acc.nonce < tx.nonce)
     298 UBC           0 :         return make_error_code(NONCE_TOO_HIGH);
     299                 : 
     300 CBC          53 :     if (sender_acc.nonce > tx.nonce)
     301 UBC           0 :         return make_error_code(NONCE_TOO_LOW);
     302                 : 
     303                 :     // initcode size is limited by EIP-3860.
     304 CBC          53 :     if (rev >= EVMC_SHANGHAI && !tx.to.has_value() && tx.data.size() > max_initcode_size)
     305 UBC           0 :         return make_error_code(INIT_CODE_SIZE_LIMIT_EXCEEDED);
     306                 : 
     307                 :     // Compute and check if sender has enough balance for the theoretical maximum transaction cost.
     308                 :     // Note this is different from tx_max_cost computed with effective gas price later.
     309                 :     // The computation cannot overflow if done with 512-bit precision.
     310 CBC          53 :     auto max_total_fee = umul(intx::uint256{tx.gas_limit}, tx.max_gas_price);
     311              53 :     max_total_fee += tx.value;
     312                 : 
     313              53 :     if (tx.type == Transaction::Type::blob)
     314                 :     {
     315 UBC           0 :         const auto total_blob_gas = tx.blob_gas_used();
     316                 :         // FIXME: Can overflow uint256.
     317               0 :         max_total_fee += total_blob_gas * tx.max_blob_gas_price;
     318                 :     }
     319 CBC          53 :     if (sender_acc.balance < max_total_fee)
     320 UBC           0 :         return make_error_code(INSUFFICIENT_FUNDS);
     321                 : 
     322 CBC          53 :     const auto execution_gas_limit = tx.gas_limit - compute_tx_intrinsic_cost(rev, tx);
     323              53 :     if (execution_gas_limit < 0)
     324 UBC           0 :         return make_error_code(INTRINSIC_GAS_TOO_LOW);
     325                 : 
     326 CBC          53 :     return execution_gas_limit;
     327                 : }
     328                 : 
     329                 : namespace
     330                 : {
     331                 : /// Deletes "touched" (marked as erasable) empty accounts in the state.
     332             106 : void delete_empty_accounts(State& state)
     333                 : {
     334             106 :     std::erase_if(state.get_accounts(), [](const std::pair<const address, Account>& p) noexcept {
     335             424 :         const auto& acc = p.second;
     336             424 :         return acc.erase_if_empty && acc.is_empty();
     337                 :     });
     338             106 : }
     339                 : }  // namespace
     340                 : 
     341 UBC           0 : void system_call(State& state, const BlockInfo& block, evmc_revision rev, evmc::VM& vm)
     342                 : {
     343                 :     static constexpr auto SystemAddress = 0xfffffffffffffffffffffffffffffffffffffffe_address;
     344                 :     static constexpr auto BeaconRootsAddress = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02_address;
     345                 : 
     346               0 :     if (rev >= EVMC_CANCUN)
     347                 :     {
     348               0 :         if (const auto acc = state.find(BeaconRootsAddress); acc != nullptr)
     349                 :         {
     350               0 :             const evmc_message msg{
     351                 :                 .kind = EVMC_CALL,
     352                 :                 .gas = 30'000'000,
     353                 :                 .recipient = BeaconRootsAddress,
     354                 :                 .sender = SystemAddress,
     355               0 :                 .input_data = block.parent_beacon_block_root.bytes,
     356                 :                 .input_size = sizeof(block.parent_beacon_block_root),
     357               0 :             };
     358                 : 
     359               0 :             const Transaction empty_tx{};
     360               0 :             Host host{rev, vm, state, block, empty_tx};
     361               0 :             const auto& code = acc->code;
     362               0 :             [[maybe_unused]] const auto res = vm.execute(host, rev, msg, code.data(), code.size());
     363               0 :             assert(res.status_code == EVMC_SUCCESS);
     364               0 :             assert(acc->access_status == EVMC_ACCESS_COLD);
     365                 : 
     366                 :             // Reset storage status.
     367               0 :             for (auto& [_, val] : acc->storage)
     368                 :             {
     369               0 :                 val.access_status = EVMC_ACCESS_COLD;
     370               0 :                 val.original = val.current;
     371                 :             }
     372               0 :         }
     373                 :     }
     374               0 : }
     375                 : 
     376 CBC          53 : void finalize(State& state, evmc_revision rev, const address& coinbase,
     377                 :     std::optional<uint64_t> block_reward, std::span<const Ommer> ommers,
     378                 :     std::span<const Withdrawal> withdrawals)
     379                 : {
     380                 :     // TODO: The block reward can be represented as a withdrawal.
     381              53 :     if (block_reward.has_value())
     382                 :     {
     383              53 :         const auto reward = *block_reward;
     384              53 :         assert(reward % 32 == 0);  // Assume block reward is divisible by 32.
     385              53 :         const auto reward_by_32 = reward / 32;
     386              53 :         const auto reward_by_8 = reward / 8;
     387                 : 
     388              53 :         state.touch(coinbase).balance += reward + reward_by_32 * ommers.size();
     389              53 :         for (const auto& ommer : ommers)
     390                 :         {
     391 UBC           0 :             assert(ommer.delta > 0 && ommer.delta < 8);
     392               0 :             state.touch(ommer.beneficiary).balance += reward_by_8 * (8 - ommer.delta);
     393                 :         }
     394                 :     }
     395                 : 
     396 CBC          53 :     for (const auto& withdrawal : withdrawals)
     397 UBC           0 :         state.touch(withdrawal.recipient).balance += withdrawal.get_amount();
     398                 : 
     399                 :     // Delete potentially empty block reward recipients.
     400 CBC          53 :     if (rev >= EVMC_SPURIOUS_DRAGON)
     401              53 :         delete_empty_accounts(state);
     402              53 : }
     403                 : 
     404              53 : std::variant<TransactionReceipt, std::error_code> transition(State& state, const BlockInfo& block,
     405                 :     const Transaction& tx, evmc_revision rev, evmc::VM& vm, int64_t block_gas_left,
     406                 :     int64_t blob_gas_left)
     407                 : {
     408              53 :     auto* sender_ptr = state.find(tx.sender);
     409                 : 
     410                 :     // Validate transaction. The validation needs the sender account, so in case
     411                 :     // it doesn't exist provide an empty one. The account isn't created in the state
     412                 :     // to prevent the state modification in case the transaction is invalid.
     413                 :     const auto validation_result =
     414              53 :         validate_transaction((sender_ptr != nullptr) ? *sender_ptr : Account{}, block, tx, rev,
     415                 :             block_gas_left, blob_gas_left);
     416                 : 
     417              53 :     if (holds_alternative<std::error_code>(validation_result))
     418 UBC           0 :         return get<std::error_code>(validation_result);
     419                 : 
     420                 :     // Once the transaction is valid, create new sender account.
     421                 :     // The account won't be empty because its nonce will be bumped.
     422 CBC          53 :     auto& sender_acc = (sender_ptr != nullptr) ? *sender_ptr : state.insert(tx.sender);
     423                 : 
     424              53 :     const auto execution_gas_limit = get<int64_t>(validation_result);
     425                 : 
     426              53 :     const auto base_fee = (rev >= EVMC_LONDON) ? block.base_fee : 0;
     427              53 :     assert(tx.max_gas_price >= base_fee);                   // Checked at the front.
     428              53 :     assert(tx.max_gas_price >= tx.max_priority_gas_price);  // Checked at the front.
     429                 :     const auto priority_gas_price =
     430              53 :         std::min(tx.max_priority_gas_price, tx.max_gas_price - base_fee);
     431              53 :     const auto effective_gas_price = base_fee + priority_gas_price;
     432                 : 
     433              53 :     assert(effective_gas_price <= tx.max_gas_price);
     434              53 :     const auto tx_max_cost = tx.gas_limit * effective_gas_price;
     435                 : 
     436              53 :     sender_acc.balance -= tx_max_cost;  // Modify sender balance after all checks.
     437                 : 
     438              53 :     if (tx.type == Transaction::Type::blob)
     439                 :     {
     440 UBC           0 :         const auto blob_fee = tx.blob_gas_used() * block.blob_base_fee;
     441               0 :         assert(sender_acc.balance >= blob_fee);  // Checked at the front.
     442               0 :         sender_acc.balance -= blob_fee;
     443                 :     }
     444                 : 
     445 CBC          53 :     Host host{rev, vm, state, block, tx};
     446                 : 
     447              53 :     sender_acc.access_status = EVMC_ACCESS_WARM;  // Tx sender is always warm.
     448              53 :     if (tx.to.has_value())
     449              53 :         host.access_account(*tx.to);
     450              53 :     for (const auto& [a, storage_keys] : tx.access_list)
     451                 :     {
     452 UBC           0 :         host.access_account(a);  // TODO: Return account ref.
     453               0 :         auto& storage = state.get(a).storage;
     454               0 :         for (const auto& key : storage_keys)
     455               0 :             storage[key].access_status = EVMC_ACCESS_WARM;
     456                 :     }
     457                 :     // EIP-3651: Warm COINBASE.
     458                 :     // This may create an empty coinbase account. The account cannot be created unconditionally
     459                 :     // because this breaks old revisions.
     460 CBC          53 :     if (rev >= EVMC_SHANGHAI)
     461              53 :         host.access_account(block.coinbase);
     462                 : 
     463              53 :     const auto result = host.call(build_message(tx, execution_gas_limit));
     464                 : 
     465              53 :     auto gas_used = tx.gas_limit - result.gas_left;
     466                 : 
     467              53 :     const auto max_refund_quotient = rev >= EVMC_LONDON ? 5 : 2;
     468              53 :     const auto refund_limit = gas_used / max_refund_quotient;
     469              53 :     const auto refund = std::min(result.gas_refund, refund_limit);
     470              53 :     gas_used -= refund;
     471              53 :     assert(gas_used > 0);
     472                 : 
     473              53 :     sender_acc.balance += tx_max_cost - gas_used * effective_gas_price;
     474              53 :     state.touch(block.coinbase).balance += gas_used * priority_gas_price;
     475                 : 
     476                 :     // Apply destructs.
     477              53 :     std::erase_if(state.get_accounts(),
     478             212 :         [](const std::pair<const address, Account>& p) noexcept { return p.second.destructed; });
     479                 : 
     480                 :     // Cumulative gas used is unknown in this scope.
     481              53 :     TransactionReceipt receipt{tx.type, result.status_code, gas_used, {}, host.take_logs(), {}, {}};
     482                 : 
     483                 :     // Cannot put it into constructor call because logs are std::moved from host instance.
     484              53 :     receipt.logs_bloom_filter = compute_bloom_filter(receipt.logs);
     485                 : 
     486                 :     // Delete empty accounts after every transaction. This is strictly required until Byzantium
     487                 :     // where intermediate state root hashes are part of the transaction receipt.
     488                 :     // TODO: Consider limiting this only to Spurious Dragon.
     489              53 :     if (rev >= EVMC_SPURIOUS_DRAGON)
     490              53 :         delete_empty_accounts(state);
     491                 : 
     492                 :     // Post-transaction clean-up.
     493                 :     // - Set accounts and their storage access status to cold.
     494                 :     // - Clear the "just created" account flag.
     495             265 :     for (auto& [addr, acc] : state.get_accounts())
     496                 :     {
     497             212 :         acc.transient_storage.clear();
     498             212 :         acc.access_status = EVMC_ACCESS_COLD;
     499             212 :         acc.just_created = false;
     500             499 :         for (auto& [key, val] : acc.storage)
     501                 :         {
     502             287 :             val.access_status = EVMC_ACCESS_COLD;
     503             287 :             val.original = val.current;
     504                 :         }
     505                 :     }
     506                 : 
     507              53 :     return receipt;
     508              53 : }
     509                 : 
     510 UBC           0 : [[nodiscard]] bytes rlp_encode(const Log& log)
     511                 : {
     512               0 :     return rlp::encode_tuple(log.addr, log.topics, log.data);
     513                 : }
     514                 : 
     515 CBC         106 : [[nodiscard]] bytes rlp_encode(const Transaction& tx)
     516                 : {
     517             106 :     assert(tx.type <= Transaction::Type::blob);
     518                 : 
     519                 :     // TODO: Refactor this function. For all type of transactions most of the code is similar.
     520             106 :     if (tx.type == Transaction::Type::legacy)
     521                 :     {
     522                 :         // rlp [nonce, gas_price, gas_limit, to, value, data, v, r, s];
     523 UBC           0 :         return rlp::encode_tuple(tx.nonce, tx.max_gas_price, static_cast<uint64_t>(tx.gas_limit),
     524 GBC         208 :             tx.to.has_value() ? tx.to.value() : bytes_view(), tx.value, tx.data, tx.v, tx.r, tx.s);
     525                 :     }
     526 CBC           2 :     else if (tx.type == Transaction::Type::access_list)
     527                 :     {
     528 UBC           0 :         if (tx.v > 1)
     529               0 :             throw std::invalid_argument("`v` value for eip2930 transaction must be 0 or 1");
     530                 :         // tx_type +
     531                 :         // rlp [nonce, gas_price, gas_limit, to, value, data, access_list, v, r, s];
     532               0 :         return bytes{0x01} +  // Transaction type (eip2930 type == 1)
     533               0 :                rlp::encode_tuple(tx.chain_id, tx.nonce, tx.max_gas_price,
     534               0 :                    static_cast<uint64_t>(tx.gas_limit),
     535               0 :                    tx.to.has_value() ? tx.to.value() : bytes_view(), tx.value, tx.data,
     536               0 :                    tx.access_list, static_cast<bool>(tx.v), tx.r, tx.s);
     537                 :     }
     538 CBC           2 :     else if (tx.type == Transaction::Type::eip1559)
     539                 :     {
     540               2 :         if (tx.v > 1)
     541 UBC           0 :             throw std::invalid_argument("`v` value for eip1559 transaction must be 0 or 1");
     542                 :         // tx_type +
     543                 :         // rlp [chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value,
     544                 :         // data, access_list, sig_parity, r, s];
     545 CBC           4 :         return bytes{0x02} +  // Transaction type (eip1559 type == 2)
     546               2 :                rlp::encode_tuple(tx.chain_id, tx.nonce, tx.max_priority_gas_price, tx.max_gas_price,
     547               2 :                    static_cast<uint64_t>(tx.gas_limit),
     548               2 :                    tx.to.has_value() ? tx.to.value() : bytes_view(), tx.value, tx.data,
     549               6 :                    tx.access_list, static_cast<bool>(tx.v), tx.r, tx.s);
     550                 :     }
     551                 :     else  // Transaction::Type::blob
     552                 :     {
     553 UBC           0 :         if (tx.v > 1)
     554               0 :             throw std::invalid_argument("`v` value for blob transaction must be 0 or 1");
     555               0 :         if (!tx.to.has_value())  // Blob tx has to have `to` address
     556               0 :             throw std::invalid_argument("`to` value for blob transaction must not be null");
     557                 :         // tx_type +
     558                 :         // rlp [chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value,
     559                 :         // data, access_list, max_fee_per_blob_gas, blob_versioned_hashes, sig_parity, r, s];
     560               0 :         return bytes{stdx::to_underlying(Transaction::Type::blob)} +
     561               0 :                rlp::encode_tuple(tx.chain_id, tx.nonce, tx.max_priority_gas_price, tx.max_gas_price,
     562               0 :                    static_cast<uint64_t>(tx.gas_limit), tx.to.value(), tx.value, tx.data,
     563               0 :                    tx.access_list, tx.max_blob_gas_price, tx.blob_hashes, static_cast<bool>(tx.v),
     564               0 :                    tx.r, tx.s);
     565                 :     }
     566                 : }
     567                 : 
     568 CBC          53 : [[nodiscard]] bytes rlp_encode(const TransactionReceipt& receipt)
     569                 : {
     570              53 :     if (receipt.post_state.has_value())
     571                 :     {
     572 UBC           0 :         assert(receipt.type == Transaction::Type::legacy);
     573                 : 
     574                 :         return rlp::encode_tuple(receipt.post_state.value(),
     575               0 :             static_cast<uint64_t>(receipt.cumulative_gas_used),
     576               0 :             bytes_view(receipt.logs_bloom_filter), receipt.logs);
     577                 :     }
     578                 :     else
     579                 :     {
     580 CBC          53 :         const auto prefix = receipt.type == Transaction::Type::legacy ?
     581                 :                                 bytes{} :
     582              54 :                                 bytes{stdx::to_underlying(receipt.type)};
     583                 : 
     584              53 :         return prefix + rlp::encode_tuple(receipt.status == EVMC_SUCCESS,
     585              53 :                             static_cast<uint64_t>(receipt.cumulative_gas_used),
     586             106 :                             bytes_view(receipt.logs_bloom_filter), receipt.logs);
     587              53 :     }
     588                 : }
     589                 : 
     590 UBC           0 : [[nodiscard]] bytes rlp_encode(const Withdrawal& withdrawal)
     591                 : {
     592               0 :     return rlp::encode_tuple(withdrawal.index, withdrawal.validator_index, withdrawal.recipient,
     593               0 :         withdrawal.amount_in_gwei);
     594                 : }
     595                 : 
     596                 : }  // namespace evmone::state
        

Generated by: LCOV version 2.0-1