Bitcoin ABC  0.29.2
P2P Digital Currency
invrequest.h
Go to the documentation of this file.
1 // Copyright (c) 2020 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_INVREQUEST_H
6 #define BITCOIN_INVREQUEST_H
7 
8 #include <net.h> // For NodeId
9 
10 #include <chrono>
11 #include <cstdint>
12 #include <functional>
13 #include <vector>
14 
120 // Avoid littering this header file with implementation details.
122  template <class InvId> friend class InvRequestTracker;
123 
124  // The base class is responsible for building the child implementation.
125  // This is a hack that allows for hiding the concrete implementation details
126  // from the callsite.
127  static std::unique_ptr<InvRequestTrackerImplInterface>
128  BuildImpl(bool deterministic);
129 
130 public:
131  using ClearExpiredFun = const std::function<void()> &;
133  const std::function<void(const NodeId &, const uint256 &)> &;
134 
135  virtual ~InvRequestTrackerImplInterface() = default;
136 
137  virtual void ReceivedInv(NodeId peer, const uint256 &invid, bool preferred,
138  std::chrono::microseconds reqtime) = 0;
139  virtual void DisconnectedPeer(NodeId peer) = 0;
140  virtual void ForgetInvId(const uint256 &invid) = 0;
141  virtual std::vector<uint256>
142  GetRequestable(NodeId peer, std::chrono::microseconds now,
143  ClearExpiredFun clearExpired,
144  EmplaceExpiredFun emplaceExpired) = 0;
145  virtual void RequestedData(NodeId peer, const uint256 &invid,
146  std::chrono::microseconds expiry) = 0;
147  virtual void ReceivedResponse(NodeId peer, const uint256 &invid) = 0;
148  virtual size_t CountInFlight(NodeId peer) const = 0;
149  virtual size_t CountCandidates(NodeId peer) const = 0;
150  virtual size_t Count(NodeId peer) const = 0;
151  virtual size_t Size() const = 0;
152  virtual uint64_t ComputePriority(const uint256 &invid, NodeId peer,
153  bool preferred) const = 0;
154  virtual void SanityCheck() const = 0;
155  virtual void
156  PostGetRequestableSanityCheck(std::chrono::microseconds now) const = 0;
157 };
158 
159 template <class InvId> class InvRequestTracker {
160  /*
161  * Only uint256-based InvId types are supported for now.
162  * FIXME: use a template constraint when C++20 is available.
163  */
164  static_assert(std::is_base_of<uint256, InvId>::value,
165  "InvRequestTracker inv id type should be uint256 or derived");
166 
167  const std::unique_ptr<InvRequestTrackerImplInterface> m_impl;
168 
169 public:
171  explicit InvRequestTracker(bool deterministic = false)
172  : m_impl{InvRequestTrackerImplInterface::BuildImpl(deterministic)} {}
173  ~InvRequestTracker() = default;
174 
175  // Conceptually, the data structure consists of a collection of
176  // "announcements", one for each peer/invid combination:
177  //
178  // - CANDIDATE announcements represent inventories that were announced by a
179  // peer, and that become available for download after their reqtime has
180  // passed.
181  //
182  // - REQUESTED announcements represent inventories that have been
183  // requested, and which we're awaiting a response for from that peer.
184  // Their expiry value determines when the request times out.
185  //
186  // - COMPLETED announcements represent inventories that have been requested
187  // from a peer, and a NOTFOUND or an inventory was received in response
188  // (valid or not), or they timed out. They're only kept around to prevent
189  // requesting them again. If only COMPLETED announcements for a given
190  // invid remain (so no CANDIDATE or REQUESTED ones), all of them are
191  // deleted (this is an invariant, and maintained by all operations below).
192  //
193  // The operations below manipulate the data structure.
194 
201  void ReceivedInv(NodeId peer, const InvId &invid, bool preferred,
202  std::chrono::microseconds reqtime) {
203  m_impl->ReceivedInv(peer, invid, preferred, reqtime);
204  }
205 
211  void DisconnectedPeer(NodeId peer) { m_impl->DisconnectedPeer(peer); }
212 
220  void ForgetInvId(const InvId &invid) { m_impl->ForgetInvId(invid); }
221 
244  std::vector<InvId>
245  GetRequestable(NodeId peer, std::chrono::microseconds now,
246  std::vector<std::pair<NodeId, InvId>> *expired) {
248  [expired]() {
249  if (expired) {
250  expired->clear();
251  }
252  };
254  [expired](const NodeId &nodeid, const uint256 &invid) {
255  if (expired) {
256  expired->emplace_back(nodeid, InvId(invid));
257  }
258  };
259  std::vector<uint256> hashes =
260  m_impl->GetRequestable(peer, now, clearExpired, emplaceExpired);
261  return std::vector<InvId>(hashes.begin(), hashes.end());
262  }
263 
275  void RequestedData(NodeId peer, const InvId &invid,
276  std::chrono::microseconds expiry) {
277  m_impl->RequestedData(peer, invid, expiry);
278  }
279 
289  void ReceivedResponse(NodeId peer, const InvId &invid) {
290  m_impl->ReceivedResponse(peer, invid);
291  }
292 
293  // The operations below inspect the data structure.
294 
296  size_t CountInFlight(NodeId peer) const {
297  return m_impl->CountInFlight(peer);
298  }
299 
301  size_t CountCandidates(NodeId peer) const {
302  return m_impl->CountCandidates(peer);
303  }
304 
309  size_t Count(NodeId peer) const { return m_impl->Count(peer); }
310 
315  size_t Size() const { return m_impl->Size(); }
316 
318  uint64_t ComputePriority(const InvId &invid, NodeId peer,
319  bool preferred) const {
320  return m_impl->ComputePriority(invid, peer, preferred);
321  }
322 
324  void SanityCheck() const { m_impl->SanityCheck(); }
325 
332  void PostGetRequestableSanityCheck(std::chrono::microseconds now) const {
333  m_impl->PostGetRequestableSanityCheck(now);
334  }
335 };
336 
337 #endif // BITCOIN_INVREQUEST_H
~InvRequestTracker()=default
size_t Size() const
Count how many announcements are being tracked in total across all peers and inventory ids.
Definition: invrequest.h:315
const std::unique_ptr< InvRequestTrackerImplInterface > m_impl
Definition: invrequest.h:165
InvRequestTracker(bool deterministic=false)
Construct a InvRequestTracker.
Definition: invrequest.h:171
void RequestedData(NodeId peer, const InvId &invid, std::chrono::microseconds expiry)
Marks an inventory as requested, with a specified expiry.
Definition: invrequest.h:275
void ForgetInvId(const InvId &invid)
Deletes all announcements for a given invid.
Definition: invrequest.h:220
void DisconnectedPeer(NodeId peer)
Deletes all announcements for a given peer.
Definition: invrequest.h:211
void SanityCheck() const
Run internal consistency check (testing only).
Definition: invrequest.h:324
uint64_t ComputePriority(const InvId &invid, NodeId peer, bool preferred) const
Access to the internal priority computation (testing only)
Definition: invrequest.h:318
void PostGetRequestableSanityCheck(std::chrono::microseconds now) const
Run a time-dependent internal consistency check (testing only).
Definition: invrequest.h:332
size_t Count(NodeId peer) const
Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined).
Definition: invrequest.h:309
size_t CountCandidates(NodeId peer) const
Count how many CANDIDATE announcements a peer has.
Definition: invrequest.h:301
void ReceivedInv(NodeId peer, const InvId &invid, bool preferred, std::chrono::microseconds reqtime)
Adds a new CANDIDATE announcement.
Definition: invrequest.h:201
void ReceivedResponse(NodeId peer, const InvId &invid)
Converts a CANDIDATE or REQUESTED announcement to a COMPLETED one.
Definition: invrequest.h:289
size_t CountInFlight(NodeId peer) const
Count how many REQUESTED announcements a peer has.
Definition: invrequest.h:296
std::vector< InvId > GetRequestable(NodeId peer, std::chrono::microseconds now, std::vector< std::pair< NodeId, InvId >> *expired)
Find the invids to request now from peer.
Definition: invrequest.h:245
Data structure to keep track of, and schedule, inventory downloads from peers.
Definition: invrequest.h:121
virtual void ReceivedInv(NodeId peer, const uint256 &invid, bool preferred, std::chrono::microseconds reqtime)=0
virtual std::vector< uint256 > GetRequestable(NodeId peer, std::chrono::microseconds now, ClearExpiredFun clearExpired, EmplaceExpiredFun emplaceExpired)=0
static std::unique_ptr< InvRequestTrackerImplInterface > BuildImpl(bool deterministic)
Definition: invrequest.cpp:863
virtual void RequestedData(NodeId peer, const uint256 &invid, std::chrono::microseconds expiry)=0
virtual void ForgetInvId(const uint256 &invid)=0
virtual void DisconnectedPeer(NodeId peer)=0
virtual size_t CountInFlight(NodeId peer) const =0
virtual void ReceivedResponse(NodeId peer, const uint256 &invid)=0
virtual void SanityCheck() const =0
virtual size_t Size() const =0
virtual size_t Count(NodeId peer) const =0
virtual uint64_t ComputePriority(const uint256 &invid, NodeId peer, bool preferred) const =0
virtual ~InvRequestTrackerImplInterface()=default
const std::function< void()> & ClearExpiredFun
Definition: invrequest.h:131
virtual size_t CountCandidates(NodeId peer) const =0
const std::function< void(const NodeId &, const uint256 &)> & EmplaceExpiredFun
Definition: invrequest.h:133
virtual void PostGetRequestableSanityCheck(std::chrono::microseconds now) const =0
256-bit opaque blob.
Definition: uint256.h:129
int64_t NodeId
Definition: nodeid.h:10