LCOV - code coverage report
Current view: top level - src - private_broadcast.h (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 100.0 % 15 15
Test Date: 2026-07-15 08:23:38 Functions: 100.0 % 2 2
Branches: 50.0 % 12 6

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2023-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or https://opensource.org/license/mit/.
       4                 :             : 
       5                 :             : #ifndef BITCOIN_PRIVATE_BROADCAST_H
       6                 :             : #define BITCOIN_PRIVATE_BROADCAST_H
       7                 :             : 
       8                 :             : #include <net.h>
       9                 :             : #include <primitives/transaction.h>
      10                 :             : #include <primitives/transaction_identifier.h>
      11                 :             : #include <sync.h>
      12                 :             : #include <util/time.h>
      13                 :             : 
      14                 :             : #include <optional>
      15                 :             : #include <tuple>
      16                 :             : #include <unordered_map>
      17                 :             : #include <vector>
      18                 :             : 
      19                 :             : /**
      20                 :             :  * Store a list of transactions to be broadcast privately. Supports the following operations:
      21                 :             :  * - Add a new transaction
      22                 :             :  * - Remove a transaction
      23                 :             :  * - Pick a transaction for sending to one recipient
      24                 :             :  * - Query which transaction has been picked for sending to a given recipient node
      25                 :             :  * - Mark that a given recipient node has confirmed receipt of a transaction
      26                 :             :  * - Query whether a given recipient node has confirmed reception
      27                 :             :  * - Query whether any transactions that need sending are currently on the list
      28                 :             :  */
      29                 :           3 : class PrivateBroadcast
      30                 :             : {
      31                 :             : public:
      32                 :             : 
      33                 :             :     /// If a transaction is not sent to any peer for this duration,
      34                 :             :     /// then we consider it stale / for rebroadcasting.
      35                 :             :     static constexpr auto INITIAL_STALE_DURATION{5min};
      36                 :             : 
      37                 :             :     /// If a transaction is not received back from the network for this duration
      38                 :             :     /// after it is broadcast, then we consider it stale / for rebroadcasting.
      39                 :             :     static constexpr auto STALE_DURATION{1min};
      40                 :             : 
      41                 :             :     /// Maximum number of transactions tracked simultaneously.
      42                 :             :     /// Additions that would exceed this are rejected (see Add()).
      43                 :             :     static constexpr size_t MAX_TRANSACTIONS{10'000};
      44                 :             : 
      45                 :             :     /// @param[in] max_transactions Cap on the number of simultaneously tracked
      46                 :             :     /// transactions. Defaults to MAX_TRANSACTIONS.
      47                 :         168 :     explicit PrivateBroadcast(size_t max_transactions = MAX_TRANSACTIONS)
      48 [ -  + ][ +  -  :         168 :         : m_max_transactions{max_transactions} {}
             +  -  +  - ]
      49                 :             : 
      50                 :          12 :     struct PeerSendInfo {
      51                 :             :         CService address;
      52                 :             :         NodeClock::time_point sent;
      53                 :             :         std::optional<NodeClock::time_point> received;
      54                 :             :     };
      55                 :             : 
      56                 :       70005 :     struct TxBroadcastInfo {
      57                 :             :         CTransactionRef tx;
      58                 :             :         NodeClock::time_point time_added;
      59                 :             :         std::vector<PeerSendInfo> peers;
      60                 :             :     };
      61                 :             : 
      62                 :             :     /// Outcome of Add().
      63                 :             :     enum class AddResult {
      64                 :             :         //! The transaction was newly added.
      65                 :             :         Added,
      66                 :             :         //! The transaction was already present; no change.
      67                 :             :         AlreadyPresent,
      68                 :             :         //! Rejected: the queue is already at MAX_TRANSACTIONS.
      69                 :             :         QueueFull,
      70                 :             :     };
      71                 :             : 
      72                 :             :     /**
      73                 :             :      * Add a transaction to the storage.
      74                 :             :      * @param[in] tx The transaction to add.
      75                 :             :      * @return Whether the transaction was newly added, was already present, or
      76                 :             :      * was rejected because the queue is full (see AddResult).
      77                 :             :      */
      78                 :             :     [[nodiscard]] AddResult Add(const CTransactionRef& tx)
      79                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
      80                 :             : 
      81                 :             :     /**
      82                 :             :      * Forget a transaction.
      83                 :             :      * @param[in] tx Transaction to forget.
      84                 :             :      * @retval !nullopt The number of times the transaction was sent and confirmed
      85                 :             :      * by the recipient (if the transaction existed and was removed).
      86                 :             :      * @retval nullopt The transaction was not in the storage.
      87                 :             :      */
      88                 :             :     std::optional<size_t> Remove(const CTransactionRef& tx)
      89                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
      90                 :             : 
      91                 :             :     /**
      92                 :             :      * Pick the transaction with the fewest send attempts, and confirmations,
      93                 :             :      * and oldest send/confirm times.
      94                 :             :      * @param[in] will_send_to_nodeid Will remember that the returned transaction
      95                 :             :      * was picked for sending to this node. Calling this method more than once with
      96                 :             :      * the same `will_send_to_nodeid` is not allowed because sending more than one
      97                 :             :      * transaction to one node would be a privacy leak.
      98                 :             :      * @param[in] will_send_to_address Address of the peer to which this transaction
      99                 :             :      * will be sent.
     100                 :             :      * @return Most urgent transaction or nullopt if there are no transactions.
     101                 :             :      */
     102                 :             :     std::optional<CTransactionRef> PickTxForSend(const NodeId& will_send_to_nodeid, const CService& will_send_to_address)
     103                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
     104                 :             : 
     105                 :             :     /**
     106                 :             :      * Get the transaction that was picked for sending to a given node by PickTxForSend().
     107                 :             :      * @param[in] nodeid Node to which a transaction is being (or was) sent.
     108                 :             :      * @return Transaction or nullopt if the nodeid is unknown.
     109                 :             :      */
     110                 :             :     std::optional<CTransactionRef> GetTxForNode(const NodeId& nodeid)
     111                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
     112                 :             : 
     113                 :             :     /**
     114                 :             :      * Mark that the node has confirmed reception of the transaction we sent it by
     115                 :             :      * responding with `PONG` to our `PING` message.
     116                 :             :      * @param[in] nodeid Node that we sent a transaction to.
     117                 :             :      */
     118                 :             :     void NodeConfirmedReception(const NodeId& nodeid)
     119                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
     120                 :             : 
     121                 :             :     /**
     122                 :             :      * Check if the node has confirmed reception of the transaction.
     123                 :             :      * @retval true Node has confirmed, `NodeConfirmedReception()` has been called.
     124                 :             :      * @retval false Node has not confirmed, `NodeConfirmedReception()` has not been called.
     125                 :             :      */
     126                 :             :     bool DidNodeConfirmReception(const NodeId& nodeid)
     127                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
     128                 :             : 
     129                 :             :     /**
     130                 :             :      * Check if there are transactions that need to be broadcast.
     131                 :             :      */
     132                 :             :     bool HavePendingTransactions()
     133                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
     134                 :             : 
     135                 :             :     /**
     136                 :             :      * Get the transactions that have not been broadcast recently.
     137                 :             :      */
     138                 :             :     std::vector<CTransactionRef> GetStale() const
     139                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
     140                 :             : 
     141                 :             :     /**
     142                 :             :      * Get stats about all transactions currently being privately broadcast.
     143                 :             :      */
     144                 :             :     std::vector<TxBroadcastInfo> GetBroadcastInfo() const
     145                 :             :         EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
     146                 :             : 
     147                 :             : private:
     148                 :             :     /// Status of a transaction sent to a given node.
     149                 :           2 :     struct SendStatus {
     150                 :             :         /// Node to which the transaction will be sent (or was sent).
     151                 :             :         const NodeId nodeid;
     152                 :             :         /// Address of the node.
     153                 :             :         const CService address;
     154                 :             :         /// When was the transaction picked for sending to the node.
     155                 :             :         const NodeClock::time_point picked;
     156                 :             :         /// When was the transaction reception confirmed by the node (by PONG).
     157                 :             :         std::optional<NodeClock::time_point> confirmed;
     158                 :             : 
     159                 :           2 :         SendStatus(const NodeId& nodeid, const CService& address, const NodeClock::time_point& picked) : nodeid{nodeid}, address{address}, picked{picked} {}
     160                 :             :     };
     161                 :             : 
     162                 :             :     /// Cumulative stats from all the send attempts for a transaction. Used to prioritize transactions.
     163                 :             :     struct Priority {
     164                 :             :         size_t num_picked{0}; ///< Number of times the transaction was picked for sending.
     165                 :             :         NodeClock::time_point last_picked{}; ///< The most recent time when the transaction was picked for sending.
     166                 :             :         size_t num_confirmed{0}; ///< Number of nodes that have confirmed reception of a transaction (by PONG).
     167                 :             :         NodeClock::time_point last_confirmed{}; ///< The most recent time when the transaction was confirmed.
     168                 :             : 
     169                 :           2 :         auto operator<=>(const Priority& other) const
     170                 :             :         {
     171                 :             :             // Invert `other` and `this` in the comparison because smaller num_picked, num_confirmed or
     172                 :             :             // earlier times mean greater priority. In other words, if this.num_picked < other.num_picked
     173                 :             :             // then this > other.
     174                 :           2 :             return std::tie(other.num_picked, other.num_confirmed, other.last_picked, other.last_confirmed) <=>
     175                 :           2 :                    std::tie(num_picked, num_confirmed, last_picked, last_confirmed);
     176                 :             :         }
     177                 :             :     };
     178                 :             : 
     179                 :             :     /// A pair of a transaction and a sent status for a given node. Convenience return type of GetSendStatusByNode().
     180                 :             :     struct TxAndSendStatusForNode {
     181                 :             :         const CTransactionRef& tx;
     182                 :             :         SendStatus& send_status;
     183                 :             :     };
     184                 :             : 
     185                 :             :     // No need for salted hasher because we are going to store just a bunch of locally originating transactions.
     186                 :             : 
     187                 :             :     struct CTransactionRefHash {
     188                 :       20023 :         size_t operator()(const CTransactionRef& tx) const
     189                 :             :         {
     190         [ +  + ]:       20023 :             return static_cast<size_t>(tx->GetWitnessHash().ToUint256().GetUint64(0));
     191                 :             :         }
     192                 :             :     };
     193                 :             : 
     194                 :             :     struct CTransactionRefComp {
     195                 :           6 :         bool operator()(const CTransactionRef& a, const CTransactionRef& b) const
     196                 :             :         {
     197         [ -  - ]:           6 :             return a->GetWitnessHash() == b->GetWitnessHash(); // If wtxid equals, then txid also equals.
     198                 :             :         }
     199                 :             :     };
     200                 :             : 
     201                 :             :     /**
     202                 :             :      * Derive the sending priority of a transaction.
     203                 :             :      * @param[in] sent_to List of nodes that the transaction has been sent to.
     204                 :             :      */
     205                 :             :     static Priority DerivePriority(const std::vector<SendStatus>& sent_to);
     206                 :             : 
     207                 :             :     /**
     208                 :             :      * Find which transaction we sent to a given node (marked by PickTxForSend()).
     209                 :             :      * @return That transaction together with the send status or nullopt if we did not
     210                 :             :      * send any transaction to the given node.
     211                 :             :      */
     212                 :             :     std::optional<TxAndSendStatusForNode> GetSendStatusByNode(const NodeId& nodeid)
     213                 :             :         EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
     214                 :       10005 :     struct TxSendStatus {
     215                 :             :         const NodeClock::time_point time_added{NodeClock::now()};
     216                 :             :         std::vector<SendStatus> send_statuses;
     217                 :             :     };
     218                 :             :     /// Cap on the number of simultaneously tracked transactions (see Add()).
     219                 :             :     const size_t m_max_transactions;
     220                 :             :     mutable Mutex m_mutex;
     221                 :             :     std::unordered_map<CTransactionRef, TxSendStatus, CTransactionRefHash, CTransactionRefComp>
     222                 :             :         m_transactions GUARDED_BY(m_mutex);
     223                 :             : };
     224                 :             : 
     225                 :             : #endif // BITCOIN_PRIVATE_BROADCAST_H
        

Generated by: LCOV version 2.0-1