Bitcoin ABC 0.30.5
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
130public:
131 using ClearExpiredFun = const std::function<void()> &;
133 const std::function<void(const NodeId &, const uint256 &)> &;
134
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
159template <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
169public:
171 explicit InvRequestTracker(bool deterministic = false)
172 : m_impl{InvRequestTrackerImplInterface::BuildImpl(deterministic)} {}
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
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
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:167
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
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
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 std::vector< uint256 > GetRequestable(NodeId peer, std::chrono::microseconds now, ClearExpiredFun clearExpired, EmplaceExpiredFun emplaceExpired)=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