LCOV - code coverage report
Current view: top level - src/wallet - scan.h (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 11.1 % 9 1
Test Date: 2026-09-27 07:34:41 Functions: 0.0 % 3 0
Branches: 0.0 % 20 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2026-present 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                 :             : #ifndef BITCOIN_WALLET_SCAN_H
       6                 :             : #define BITCOIN_WALLET_SCAN_H
       7                 :             : 
       8                 :             : #include <uint256.h>
       9                 :             : #include <util/time.h>
      10                 :             : 
      11                 :             : #include <atomic>
      12                 :             : #include <functional>
      13                 :             : #include <optional>
      14                 :             : 
      15                 :             : namespace wallet {
      16                 :             : class CWallet;
      17                 :             : 
      18                 :             : /** Result of a wallet scan */
      19                 :             : struct ScanResult {
      20                 :             :     enum { SUCCESS, FAILURE, USER_ABORT } status = SUCCESS;
      21                 :             : 
      22                 :             :     //! Hash and height of most recent block that was successfully scanned.
      23                 :             :     //! Unset if no blocks were scanned due to read errors or the chain
      24                 :             :     //! being empty.
      25                 :             :     uint256 last_scanned_block;
      26                 :             :     std::optional<int> last_scanned_height;
      27                 :             : 
      28                 :             :     //! Height of the most recent block that could not be scanned due to
      29                 :             :     //! read errors or pruning. Will be set if status is FAILURE, unset if
      30                 :             :     //! status is SUCCESS, and may or may not be set if status is
      31                 :             :     //! USER_ABORT.
      32                 :             :     uint256 last_failed_block;
      33                 :             : };
      34                 :             : 
      35                 :             : /** RAII object to check and reserve a wallet rescan */
      36                 :             : class WalletRescanReserver
      37                 :             : {
      38                 :             : private:
      39                 :             :     using Clock = std::chrono::steady_clock;
      40                 :             :     using NowFn = std::function<Clock::time_point()>;
      41                 :             :     CWallet& m_wallet;
      42                 :             :     bool m_could_reserve{false};
      43                 :             :     NowFn m_now;
      44                 :             : public:
      45         [ #  # ]:           0 :     explicit WalletRescanReserver(CWallet& w) : m_wallet(w) {}
      46                 :             : 
      47                 :             :     bool reserve(bool with_passphrase = false);
      48                 :             :     bool isReserved() const;
      49                 :             : 
      50         [ #  # ]:           0 :     Clock::time_point now() const { return m_now ? m_now() : Clock::now(); };
      51                 :             : 
      52                 :             :     void setNow(NowFn now) { m_now = std::move(now); }
      53                 :             : 
      54                 :             :     ~WalletRescanReserver();
      55                 :             : };
      56                 :             : 
      57                 :             : class ChainScanner {
      58                 :             : private:
      59                 :             :     CWallet& m_wallet;
      60                 :             : 
      61                 :             :     std::atomic<bool> m_abort{false};
      62                 :             :     std::atomic<bool> m_scanning{false};
      63                 :             :     std::atomic<bool> m_scanning_with_passphrase{false};
      64                 :             :     std::atomic<SteadyClock::time_point> m_scanning_start{SteadyClock::time_point{}};
      65                 :             :     std::atomic<double> m_scanning_progress{0};
      66                 :             : 
      67                 :             :     //! Progress window and tip tracked across Scan loop iterations. The
      68                 :             :     //! current block's progress is a plain local in Scan; only the window
      69                 :             :     //! bounds are shared with the helpers, and UpdateTipIfChanged is the
      70                 :             :     //! sole mutator.
      71                 :             :     struct LoopState {
      72                 :             :         double progress_begin{0};
      73                 :             :         double progress_end{0};
      74                 :             :         uint256 tip_hash;
      75                 :             :     };
      76                 :             : 
      77                 :             :     //! Locate block_hash in the chain, queueing its active-chain successor
      78                 :             :     //! into next_block if it exists and is within the scan range. Returns
      79                 :             :     //! whether the block itself is still in the active chain.
      80                 :             :     bool QueueNextBlock(const uint256& block_hash, int block_height, std::optional<std::pair<uint256, int>>& next_block, std::optional<int> max_height);
      81                 :             :     bool ScanBlock(const uint256& block_hash, int block_height, bool save_progress);
      82                 :             :     void UpdateProgress(const LoopState& state, double progress_current, int block_height);
      83                 :             :     void UpdateTipIfChanged(LoopState& state);
      84                 :             : 
      85                 :             :     //! Only WalletRescanReserver may reserve and release scans, so that
      86                 :             :     //! reservations are always managed RAII-style.
      87                 :             :     friend class WalletRescanReserver;
      88                 :             :     bool TryReserve(bool with_passphrase = false);
      89                 :             :     void Release();
      90                 :             : 
      91                 :             : public:
      92                 :        9683 :     explicit ChainScanner(CWallet& wallet) : m_wallet(wallet) {}
      93                 :             : 
      94         [ #  # ]:           0 :     void Abort() { m_abort = true; }
      95         [ #  # ]:           0 :     bool IsAborting() const { return m_abort; }
      96         [ #  # ]:           0 :     bool IsScanning() const { return m_scanning; }
      97   [ #  #  #  #  :           0 :     bool IsScanningWithPassphrase() const { return m_scanning_with_passphrase; }
                   #  # ]
      98         [ #  # ]:           0 :     SteadyClock::duration ScanningDuration() const { return m_scanning ? SteadyClock::now() - m_scanning_start.load() : SteadyClock::duration{}; }
      99         [ #  # ]:           0 :     double ScanningProgress() const { return m_scanning ? m_scanning_progress.load() : 0; }
     100                 :             : 
     101                 :             :     /** Scan active chain for relevant transactions after importing keys. Should
     102                 :             :      * be called whenever new keys are added to the wallet, with the oldest key
     103                 :             :      * creation time.
     104                 :             :      * @return Earliest timestamp that could be successfully scanned from. Timestamp
     105                 :             :      * returned will be higher than startTime if relevant blocks could not be read. */
     106                 :             :     int64_t ScanFromTime(int64_t startTime, const WalletRescanReserver& reserver);
     107                 :             : 
     108                 :             :     /**
     109                 :             :      * Scan the block chain (starting in start_block) for transactions
     110                 :             :      * from or to us. If max_height is not set, the
     111                 :             :      * mempool will be scanned as well.
     112                 :             :      *
     113                 :             :      * @param[in] start_block Scan starting block. If block is not on the active
     114                 :             :      *                        chain, the scan will return SUCCESS immediately.
     115                 :             :      * @param[in] start_height Height of start_block
     116                 :             :      * @param[in] max_height  Optional max scanning height. If unset there is
     117                 :             :      *                        no maximum and scanning can continue to the tip
     118                 :             :      *
     119                 :             :      * @return ScanResult returning scan information and indicating success or
     120                 :             :      *         failure. Return status will be set to SUCCESS if scan was
     121                 :             :      *         successful. FAILURE if a complete rescan was not possible (due to
     122                 :             :      *         pruning or corruption). USER_ABORT if the rescan was aborted before
     123                 :             :      *         it could complete.
     124                 :             :      *
     125                 :             :      * @pre Caller needs to make sure start_block (and the optional stop_block) are on
     126                 :             :      * the main chain after the addition of any new keys you want to detect
     127                 :             :      * transactions for.
     128                 :             :      */
     129                 :             :     ScanResult Scan(const uint256& start_block, int start_height, std::optional<int> max_height,
     130                 :             :                     const WalletRescanReserver& reserver, bool save_progress);
     131                 :             : 
     132                 :             : };
     133                 :             : 
     134                 :             : } // namespace wallet
     135                 :             : 
     136                 :             : #endif // BITCOIN_WALLET_SCAN_H
        

Generated by: LCOV version 2.5.0-full