LCOV - code coverage report
Current view: top level - src/kernel - mempool_persist.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 3 109 2.8 %
Date: 2023-09-26 12:08:55 Functions: 3 5 60.0 %

          Line data    Source code
       1             : // Copyright (c) 2022 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <kernel/mempool_persist.h>
       6             : 
       7             : #include <clientversion.h>
       8             : #include <consensus/amount.h>
       9             : #include <logging.h>
      10             : #include <primitives/transaction.h>
      11             : #include <serialize.h>
      12             : #include <streams.h>
      13             : #include <sync.h>
      14             : #include <txmempool.h>
      15             : #include <uint256.h>
      16             : #include <util/fs.h>
      17         173 : #include <util/fs_helpers.h>
      18         173 : #include <util/signalinterrupt.h>
      19             : #include <util/time.h>
      20             : #include <validation.h>
      21             : 
      22             : #include <cstdint>
      23             : #include <cstdio>
      24             : #include <exception>
      25             : #include <functional>
      26             : #include <map>
      27             : #include <memory>
      28             : #include <set>
      29             : #include <stdexcept>
      30             : #include <utility>
      31             : #include <vector>
      32             : 
      33             : using fsbridge::FopenFn;
      34             : 
      35             : namespace kernel {
      36             : 
      37             : static const uint64_t MEMPOOL_DUMP_VERSION = 1;
      38             : 
      39           0 : bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active_chainstate, ImportMempoolOptions&& opts)
      40             : {
      41           0 :     if (load_path.empty()) return false;
      42             : 
      43           0 :     FILE* filestr{opts.mockable_fopen_function(load_path, "rb")};
      44           0 :     CAutoFile file{filestr, CLIENT_VERSION};
      45           0 :     if (file.IsNull()) {
      46           0 :         LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
      47           0 :         return false;
      48             :     }
      49             : 
      50           0 :     int64_t count = 0;
      51           0 :     int64_t expired = 0;
      52           0 :     int64_t failed = 0;
      53           0 :     int64_t already_there = 0;
      54           0 :     int64_t unbroadcast = 0;
      55           0 :     const auto now{NodeClock::now()};
      56             : 
      57             :     try {
      58             :         uint64_t version;
      59           0 :         file >> version;
      60           0 :         if (version != MEMPOOL_DUMP_VERSION) {
      61           0 :             return false;
      62             :         }
      63             :         uint64_t num;
      64           0 :         file >> num;
      65           0 :         while (num) {
      66           0 :             --num;
      67           0 :             CTransactionRef tx;
      68             :             int64_t nTime;
      69             :             int64_t nFeeDelta;
      70           0 :             file >> tx;
      71           0 :             file >> nTime;
      72           0 :             file >> nFeeDelta;
      73             : 
      74         173 :             if (opts.use_current_time) {
      75           0 :                 nTime = TicksSinceEpoch<std::chrono::seconds>(now);
      76           0 :             }
      77             : 
      78           0 :             CAmount amountdelta = nFeeDelta;
      79           0 :             if (amountdelta && opts.apply_fee_delta_priority) {
      80           0 :                 pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
      81           0 :             }
      82           0 :             if (nTime > TicksSinceEpoch<std::chrono::seconds>(now - pool.m_expiry)) {
      83           0 :                 LOCK(cs_main);
      84           0 :                 const auto& accepted = AcceptToMemoryPool(active_chainstate, tx, nTime, /*bypass_limits=*/false, /*test_accept=*/false);
      85           0 :                 if (accepted.m_result_type == MempoolAcceptResult::ResultType::VALID) {
      86           0 :                     ++count;
      87           0 :                 } else {
      88             :                     // mempool may contain the transaction already, e.g. from
      89             :                     // wallet(s) having loaded it while we were processing
      90             :                     // mempool transactions; consider these as valid, instead of
      91             :                     // failed, but mark them as 'already there'
      92           0 :                     if (pool.exists(GenTxid::Txid(tx->GetHash()))) {
      93           0 :                         ++already_there;
      94           0 :                     } else {
      95           0 :                         ++failed;
      96             :                     }
      97             :                 }
      98           0 :             } else {
      99           0 :                 ++expired;
     100             :             }
     101           0 :             if (active_chainstate.m_chainman.m_interrupt)
     102           0 :                 return false;
     103           0 :         }
     104           0 :         std::map<uint256, CAmount> mapDeltas;
     105           0 :         file >> mapDeltas;
     106             : 
     107           0 :         if (opts.apply_fee_delta_priority) {
     108           0 :             for (const auto& i : mapDeltas) {
     109           0 :                 pool.PrioritiseTransaction(i.first, i.second);
     110             :             }
     111           0 :         }
     112             : 
     113           0 :         std::set<uint256> unbroadcast_txids;
     114           0 :         file >> unbroadcast_txids;
     115           0 :         if (opts.apply_unbroadcast_set) {
     116           0 :             unbroadcast = unbroadcast_txids.size();
     117           0 :             for (const auto& txid : unbroadcast_txids) {
     118             :                 // Ensure transactions were accepted to mempool then add to
     119             :                 // unbroadcast set.
     120           0 :                 if (pool.get(txid) != nullptr) pool.AddUnbroadcastTx(txid);
     121             :             }
     122           0 :         }
     123           0 :     } catch (const std::exception& e) {
     124           0 :         LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
     125           0 :         return false;
     126           0 :     }
     127             : 
     128           0 :     LogPrintf("Imported mempool transactions from disk: %i succeeded, %i failed, %i expired, %i already there, %i waiting for initial broadcast\n", count, failed, expired, already_there, unbroadcast);
     129           0 :     return true;
     130           0 : }
     131             : 
     132           0 : bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mockable_fopen_function, bool skip_file_commit)
     133             : {
     134           0 :     auto start = SteadyClock::now();
     135             : 
     136           0 :     std::map<uint256, CAmount> mapDeltas;
     137           0 :     std::vector<TxMempoolInfo> vinfo;
     138           0 :     std::set<uint256> unbroadcast_txids;
     139             : 
     140           0 :     static Mutex dump_mutex;
     141           0 :     LOCK(dump_mutex);
     142             : 
     143             :     {
     144           0 :         LOCK(pool.cs);
     145           0 :         for (const auto &i : pool.mapDeltas) {
     146           0 :             mapDeltas[i.first] = i.second;
     147             :         }
     148           0 :         vinfo = pool.infoAll();
     149           0 :         unbroadcast_txids = pool.GetUnbroadcastTxs();
     150           0 :     }
     151             : 
     152           0 :     auto mid = SteadyClock::now();
     153             : 
     154             :     try {
     155           0 :         FILE* filestr{mockable_fopen_function(dump_path + ".new", "wb")};
     156           0 :         if (!filestr) {
     157           0 :             return false;
     158             :         }
     159             : 
     160           0 :         CAutoFile file{filestr, CLIENT_VERSION};
     161             : 
     162           0 :         uint64_t version = MEMPOOL_DUMP_VERSION;
     163           0 :         file << version;
     164             : 
     165           0 :         file << (uint64_t)vinfo.size();
     166           0 :         for (const auto& i : vinfo) {
     167           0 :             file << *(i.tx);
     168           0 :             file << int64_t{count_seconds(i.m_time)};
     169           0 :             file << int64_t{i.nFeeDelta};
     170           0 :             mapDeltas.erase(i.tx->GetHash());
     171             :         }
     172             : 
     173           0 :         file << mapDeltas;
     174             : 
     175           0 :         LogPrintf("Writing %d unbroadcast transactions to disk.\n", unbroadcast_txids.size());
     176           0 :         file << unbroadcast_txids;
     177             : 
     178           0 :         if (!skip_file_commit && !FileCommit(file.Get()))
     179           0 :             throw std::runtime_error("FileCommit failed");
     180           0 :         file.fclose();
     181           0 :         if (!RenameOver(dump_path + ".new", dump_path)) {
     182           0 :             throw std::runtime_error("Rename failed");
     183             :         }
     184           0 :         auto last = SteadyClock::now();
     185             : 
     186           0 :         LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n",
     187             :                   Ticks<SecondsDouble>(mid - start),
     188             :                   Ticks<SecondsDouble>(last - mid));
     189           0 :     } catch (const std::exception& e) {
     190           0 :         LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
     191           0 :         return false;
     192           0 :     }
     193           0 :     return true;
     194           0 : }
     195             : 
     196             : } // namespace kernel

Generated by: LCOV version 1.14