private_broadcast.cpp raw

   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  #include <private_broadcast.h>
   6  
   7  #include <util/check.h>
   8  
   9  #include <algorithm>
  10  
  11  
  12  PrivateBroadcast::AddResult PrivateBroadcast::Add(const CTransactionRef& tx)
  13      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
  14  {
  15      LOCK(m_mutex);
  16      // Re-adding an already-tracked transaction is a no-op regardless of the cap.
  17      if (m_transactions.contains(tx)) return AddResult::AlreadyPresent;
  18  
  19      if (m_transactions.size() >= m_max_transactions) return AddResult::QueueFull;
  20  
  21      m_transactions.try_emplace(tx);
  22      return AddResult::Added;
  23  }
  24  
  25  std::optional<size_t> PrivateBroadcast::Remove(const CTransactionRef& tx)
  26      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
  27  {
  28      LOCK(m_mutex);
  29      const auto handle{m_transactions.extract(tx)};
  30      if (handle) {
  31          const auto p{DerivePriority(handle.mapped().send_statuses)};
  32          return p.num_confirmed;
  33      }
  34      return std::nullopt;
  35  }
  36  
  37  std::optional<CTransactionRef> PrivateBroadcast::PickTxForSend(const NodeId& will_send_to_nodeid, const CService& will_send_to_address)
  38      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
  39  {
  40      LOCK(m_mutex);
  41  
  42      if (GetSendStatusByNode(will_send_to_nodeid).has_value()) { // nodeid reuse, shouldn't send >1 tx to a given node
  43          Assume(false);
  44          return std::nullopt;
  45      }
  46  
  47      const auto it{std::ranges::max_element(
  48              m_transactions,
  49              [](const auto& a, const auto& b) { return a < b; },
  50              [](const auto& el) { return DerivePriority(el.second.send_statuses); })};
  51  
  52      if (it != m_transactions.end()) {
  53          auto& [tx, state]{*it};
  54          state.send_statuses.emplace_back(will_send_to_nodeid, will_send_to_address, NodeClock::now());
  55          return tx;
  56      }
  57  
  58      return std::nullopt;
  59  }
  60  
  61  std::optional<CTransactionRef> PrivateBroadcast::GetTxForNode(const NodeId& nodeid)
  62      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
  63  {
  64      LOCK(m_mutex);
  65      const auto tx_and_status{GetSendStatusByNode(nodeid)};
  66      if (tx_and_status.has_value()) {
  67          return tx_and_status.value().tx;
  68      }
  69      return std::nullopt;
  70  }
  71  
  72  void PrivateBroadcast::NodeConfirmedReception(const NodeId& nodeid)
  73      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
  74  {
  75      LOCK(m_mutex);
  76      const auto tx_and_status{GetSendStatusByNode(nodeid)};
  77      if (tx_and_status.has_value()) {
  78          tx_and_status.value().send_status.confirmed = NodeClock::now();
  79      }
  80  }
  81  
  82  bool PrivateBroadcast::DidNodeConfirmReception(const NodeId& nodeid)
  83      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
  84  {
  85      LOCK(m_mutex);
  86      const auto tx_and_status{GetSendStatusByNode(nodeid)};
  87      if (tx_and_status.has_value()) {
  88          return tx_and_status.value().send_status.confirmed.has_value();
  89      }
  90      return false;
  91  }
  92  
  93  bool PrivateBroadcast::HavePendingTransactions()
  94      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
  95  {
  96      LOCK(m_mutex);
  97      return !m_transactions.empty();
  98  }
  99  
 100  std::vector<CTransactionRef> PrivateBroadcast::GetStale() const
 101      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
 102  {
 103      LOCK(m_mutex);
 104      const auto now{NodeClock::now()};
 105      std::vector<CTransactionRef> stale;
 106      for (const auto& [tx, state] : m_transactions) {
 107          const Priority p{DerivePriority(state.send_statuses)};
 108          if (p.num_confirmed == 0) {
 109              if (state.time_added < now - INITIAL_STALE_DURATION) stale.push_back(tx);
 110          } else {
 111              if (p.last_confirmed < now - STALE_DURATION) stale.push_back(tx);
 112          }
 113      }
 114      return stale;
 115  }
 116  
 117  std::vector<PrivateBroadcast::TxBroadcastInfo> PrivateBroadcast::GetBroadcastInfo() const
 118      EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
 119  {
 120      LOCK(m_mutex);
 121      std::vector<TxBroadcastInfo> entries;
 122      entries.reserve(m_transactions.size());
 123  
 124      for (const auto& [tx, state] : m_transactions) {
 125          std::vector<PeerSendInfo> peers;
 126          peers.reserve(state.send_statuses.size());
 127          for (const auto& status : state.send_statuses) {
 128              peers.emplace_back(PeerSendInfo{.address = status.address, .sent = status.picked, .received = status.confirmed});
 129          }
 130          entries.emplace_back(TxBroadcastInfo{.tx = tx, .time_added = state.time_added, .peers = std::move(peers)});
 131      }
 132  
 133      return entries;
 134  }
 135  
 136  PrivateBroadcast::Priority PrivateBroadcast::DerivePriority(const std::vector<SendStatus>& sent_to)
 137  {
 138      Priority p;
 139      p.num_picked = sent_to.size();
 140      for (const auto& send_status : sent_to) {
 141          p.last_picked = std::max(p.last_picked, send_status.picked);
 142          if (send_status.confirmed.has_value()) {
 143              ++p.num_confirmed;
 144              p.last_confirmed = std::max(p.last_confirmed, send_status.confirmed.value());
 145          }
 146      }
 147      return p;
 148  }
 149  
 150  std::optional<PrivateBroadcast::TxAndSendStatusForNode> PrivateBroadcast::GetSendStatusByNode(const NodeId& nodeid)
 151      EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
 152  {
 153      AssertLockHeld(m_mutex);
 154      for (auto& [tx, state] : m_transactions) {
 155          for (auto& send_status : state.send_statuses) {
 156              if (send_status.nodeid == nodeid) {
 157                  return TxAndSendStatusForNode{.tx = tx, .send_status = send_status};
 158              }
 159          }
 160      }
 161      return std::nullopt;
 162  }
 163