Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
peermanager.h
Go to the documentation of this file.
1// Copyright (c) 2020 The Bitcoin 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_AVALANCHE_PEERMANAGER_H
6#define BITCOIN_AVALANCHE_PEERMANAGER_H
7
8#include <avalanche/node.h>
9#include <avalanche/proof.h>
10#include <avalanche/proofpool.h>
12#include <coins.h>
13#include <common/bloom.h>
15#include <pubkey.h>
16#include <radix.h>
17#include <util/hasher.h>
18#include <util/time.h>
19
20#include <boost/multi_index/composite_key.hpp>
21#include <boost/multi_index/hashed_index.hpp>
22#include <boost/multi_index/mem_fun.hpp>
23#include <boost/multi_index/member.hpp>
24#include <boost/multi_index/ordered_index.hpp>
25#include <boost/multi_index_container.hpp>
26
27#include <atomic>
28#include <chrono>
29#include <cstdint>
30#include <memory>
31#include <vector>
32
34class CScheduler;
35
36namespace avalanche {
37
45
46class Delegation;
47
48namespace {
49 struct TestPeerManager;
50}
51
52struct Slot {
53private:
57
58public:
61
63 return Slot(startIn, score, peerid);
64 }
66 return Slot(start, scoreIn, peerid);
67 }
69 return Slot(start, score, peeridIn);
70 }
71
72 uint64_t getStart() const { return start; }
73 uint64_t getStop() const { return start + score; }
74 uint32_t getScore() const { return score; }
75 PeerId getPeerId() const { return peerid; }
76
77 bool contains(uint64_t slot) const {
78 return getStart() <= slot && slot < getStop();
79 }
80 bool precedes(uint64_t slot) const { return slot >= getStop(); }
81 bool follows(uint64_t slot) const { return getStart() > slot; }
82};
83
84struct Peer {
88
90 bool hasFinalized = false;
91
92 // The network stack uses timestamp in seconds, so we oblige.
93 std::chrono::seconds registration_time;
94 std::chrono::seconds nextPossibleConflictTime;
95
96 double availabilityScore = 0.0;
97
102 static constexpr auto DANGLING_TIMEOUT = 15min;
103
109
110 const ProofId &getProofId() const { return proof->getId(); }
111 uint32_t getScore() const { return proof->getScore(); }
112};
113
116 result_type operator()(const Peer &p) const { return p.proof->getId(); }
117};
118
121 result_type operator()(const Peer &p) const { return p.getScore(); }
122};
123
125
133
134struct by_proofid;
135struct by_nodeid;
136struct by_score;
137
141 std::chrono::seconds lastUpdate;
143};
144
156
157class ProofRegistrationState : public ValidationState<ProofRegistrationResult> {
158};
159
160namespace bmi = boost::multi_index;
161
163 std::vector<Slot> slots;
166
171 using PeerSet = boost::multi_index_container<
172 Peer, bmi::indexed_by<
173 // index by peerid
174 bmi::hashed_unique<bmi::member<Peer, PeerId, &Peer::peerid>>,
175 // index by proof
176 bmi::hashed_unique<bmi::tag<by_proofid>, proof_index,
178 // ordered by score, decreasing order
179 bmi::ordered_non_unique<bmi::tag<by_score>, score_index,
180 std::greater<uint32_t>>>>;
181
184
189
192
193 using NodeSet = boost::multi_index_container<
194 Node, bmi::indexed_by<
195 // index by nodeid
196 bmi::hashed_unique<bmi::member<Node, NodeId, &Node::nodeid>>,
197 // sorted by peerid/nextRequestTime
198 bmi::ordered_non_unique<
199 bmi::tag<next_request_time>,
200 bmi::composite_key<
201 Node, bmi::member<Node, PeerId, &Node::peerid>,
202 bmi::member<Node, SteadyMilliseconds,
204
206
211 std::atomic<bool> needMoreNodes{false};
212
213 using PendingNodeSet = boost::multi_index_container<
215 bmi::indexed_by<
216 // index by proofid
217 bmi::hashed_non_unique<
218 bmi::tag<by_proofid>,
219 bmi::member<PendingNode, ProofId, &PendingNode::proofid>,
221 // index by nodeid
222 bmi::hashed_unique<
223 bmi::tag<by_nodeid>,
224 bmi::member<PendingNode, NodeId, &PendingNode::nodeid>>>>;
226
227 static constexpr int SELECT_PEER_MAX_RETRY = 3;
228 static constexpr int SELECT_NODE_MAX_RETRY = 3;
229
234
240
242
244
246
247 struct by_lastUpdate;
248
249 using RemoteProofSet = boost::multi_index_container<
251 bmi::indexed_by<
252 // index by proofid/nodeid pair
253 bmi::hashed_unique<
254 bmi::composite_key<
256 bmi::member<RemoteProof, ProofId, &RemoteProof::proofid>,
257 bmi::member<RemoteProof, NodeId, &RemoteProof::nodeid>>,
258 bmi::composite_key_hash<SaltedProofIdHasher,
259 boost::hash<NodeId>>>,
260 // index by proofid
261 bmi::hashed_non_unique<
262 bmi::tag<by_proofid>,
263 bmi::member<RemoteProof, ProofId, &RemoteProof::proofid>,
265 // index by nodeid
266 bmi::hashed_non_unique<
267 bmi::tag<by_nodeid>,
268 bmi::member<RemoteProof, NodeId, &RemoteProof::nodeid>>,
269 bmi::ordered_non_unique<
270 bmi::tag<by_lastUpdate>,
271 bmi::composite_key<
273 bmi::member<RemoteProof, NodeId, &RemoteProof::nodeid>,
274 bmi::member<RemoteProof, std::chrono::seconds,
276
282
296
297 std::unordered_set<ProofId, SaltedProofIdHasher> manualFlakyProofids;
298
299public:
300 static constexpr size_t MAX_REMOTE_PROOFS{100};
301
307
311 bool addNode(NodeId nodeid, const ProofId &proofid);
312 bool removeNode(NodeId nodeid);
313 size_t getNodeCount() const { return nodes.size(); }
314 size_t getPendingNodeCount() const { return pendingNodes.size(); }
315
316 // Update when a node is to be polled next.
317 bool updateNextRequestTime(NodeId nodeid, SteadyMilliseconds timeout);
323 bool latchAvaproofsSent(NodeId nodeid);
324
325 // Randomly select a node to poll.
327
331 bool shouldRequestMoreNodes() { return needMoreNodes.exchange(false); }
332
333 template <typename Callable>
334 bool forNode(NodeId nodeid, Callable &&func) const {
335 auto it = nodes.find(nodeid);
336 return it != nodes.end() && func(*it);
337 }
338
339 template <typename Callable>
340 void forEachNode(const Peer &peer, Callable &&func) const {
341 auto &nview = nodes.get<next_request_time>();
342 auto range = nview.equal_range(peer.peerid);
343 for (auto it = range.first; it != range.second; ++it) {
344 func(*it);
345 }
346 }
347
357 const std::chrono::seconds &nextTime);
358
362 bool setFinalized(PeerId peerid);
363
371 enum class RegistrationMode {
372 DEFAULT,
374 };
375
376 bool registerProof(const ProofRef &proof,
379 bool registerProof(const ProofRef &proof,
382 return registerProof(proof, dummy, mode);
383 }
384
394 enum class RejectionMode {
395 DEFAULT,
397 };
398
399 bool rejectProof(const ProofId &proofid,
401
406 bool exists(const ProofId &proofid) const {
407 return getProof(proofid) != nullptr;
408 }
409
411 std::unordered_set<ProofRef, SaltedProofHasher> &registeredProofs);
412
413 template <typename Callable>
414 bool forPeer(const ProofId &proofid, Callable &&func) const {
415 auto &pview = peers.get<by_proofid>();
416 auto it = pview.find(proofid);
417 return it != pview.end() && func(*it);
418 }
419
420 template <typename Callable> void forEachPeer(Callable &&func) const {
421 for (const auto &p : peers) {
422 func(p);
423 }
424 }
425
429 std::unordered_set<ProofRef, SaltedProofHasher> updatedBlockTip();
430
434 void addUnbroadcastProof(const ProofId &proofid);
435 void removeUnbroadcastProof(const ProofId &proofid);
437
438 /*
439 * Quorum management
440 */
443
444 bool saveRemoteProof(const ProofId &proofid, const NodeId nodeid,
445 const bool present);
446 std::vector<RemoteProof> getRemoteProofs(const NodeId nodeid) const;
447 bool isRemoteProof(const ProofId &proofid) const;
448
449 bool setFlaky(const ProofId &proofid);
450 bool unsetFlaky(const ProofId &proofid);
451 template <typename Callable> void forEachFlakyProof(Callable &&func) const {
452 for (const auto &p : manualFlakyProofids) {
453 func(p);
454 }
455 }
456
457 template <typename Callable>
460 for (auto it = peers.begin(); it != peers.end(); it++) {
461 peers.modify(it, [&](Peer &peer) {
462 // Calculate average of current node scores
463 double peerScore{0.0};
464 forEachNode(peer, [&](const avalanche::Node &node) {
466 });
467
468 // Calculate exponential moving average of averaged node scores
469 peer.availabilityScore =
471 (1. - decayFactor) * peer.availabilityScore;
472 });
473 }
474 }
475
476 /****************************************************
477 * Functions which are public for testing purposes. *
478 ****************************************************/
479
483 bool removePeer(const PeerId peerid);
484
488 PeerId selectPeer() const;
489
495
499 bool verify() const;
500
501 // Accessors.
502 uint64_t getSlotCount() const { return slotCount; }
504
505 const ProofPool &getValidProofPool() const { return validProofPool; }
508 }
510
511 ProofRef getProof(const ProofId &proofid) const;
512 bool isBoundToPeer(const ProofId &proofid) const;
513 bool isImmature(const ProofId &proofid) const;
514 bool isInConflictingPool(const ProofId &proofid) const;
515 bool isDangling(const ProofId &proofid) const;
516
517 void setInvalid(const ProofId &proofid);
518 bool isInvalid(const ProofId &proofid) const;
519 void clearAllInvalid();
520
524
527 }
528
534 const CBlockIndex *pprev,
535 std::vector<std::pair<ProofId, CScript>> &winners);
536
537 bool dumpPeersToFile(const fs::path &dumpPath) const;
539 const fs::path &dumpPath,
540 std::unordered_set<ProofRef, SaltedProofHasher> &registeredProofs);
541
542private:
543 template <typename ProofContainer>
545
546 bool addOrUpdateNode(const PeerSet::iterator &it, NodeId nodeid);
547 bool addNodeToPeer(const PeerSet::iterator &it);
548 bool removeNodeFromPeer(const PeerSet::iterator &it, uint32_t count = 1);
549
557 std::optional<bool> getRemotePresenceStatus(const ProofId &proofid) const;
558
559 bool isFlaky(const ProofId &proofid) const;
560
561 friend struct ::avalanche::TestPeerManager;
562};
563
567PeerId selectPeerImpl(const std::vector<Slot> &slots, const uint64_t slot,
568 const uint64_t max);
569
570} // namespace avalanche
571
572#endif // BITCOIN_AVALANCHE_PEERMANAGER_H
uint32_t PeerId
Definition node.h:15
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition blockindex.h:25
RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
Definition bloom.h:115
Simple class for background tasks that should be run periodically or once "after a while".
Definition scheduler.h:41
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Template for capturing information about block/transaction validation.
Definition validation.h:89
bool selectStakingRewardWinner(const CBlockIndex *pprev, std::vector< std::pair< ProofId, CScript > > &winners)
Deterministically select a list of payout scripts based on the proof set and the previous block hash.
boost::multi_index_container< PendingNode, bmi::indexed_by< bmi::hashed_non_unique< bmi::tag< by_proofid >, bmi::member< PendingNode, ProofId, &PendingNode::proofid >, SaltedProofIdHasher >, bmi::hashed_unique< bmi::tag< by_nodeid >, bmi::member< PendingNode, NodeId, &PendingNode::nodeid > > > > PendingNodeSet
std::vector< RemoteProof > getRemoteProofs(const NodeId nodeid) const
bool removeNode(NodeId nodeid)
bool setFinalized(PeerId peerid)
Latch on that this peer has a finalized proof.
bool dumpPeersToFile(const fs::path &dumpPath) const
RemoteProofSet remoteProofs
Remember which node sent which proof so we have an image of the proof set of our peers.
uint64_t getFragmentation() const
uint32_t getConnectedPeersScore() const
bool isDangling(const ProofId &proofid) const
bool updateNextRequestTime(NodeId nodeid, SteadyMilliseconds timeout)
bool unsetFlaky(const ProofId &proofid)
std::optional< bool > getRemotePresenceStatus(const ProofId &proofid) const
Get the presence remote status of a proof.
bool addNodeToPeer(const PeerSet::iterator &it)
bool shouldRequestMoreNodes()
Returns true if we encountered a lack of node since the last call.
bool exists(const ProofId &proofid) const
Return true if the (valid) proof exists, but only for non-dangling proofs.
bool isRemoteProof(const ProofId &proofid) const
size_t getNodeCount() const
PendingNodeSet pendingNodes
const ProofPool & getValidProofPool() const
bool verify() const
Perform consistency check on internal data structures.
bool forNode(NodeId nodeid, Callable &&func) const
bool forPeer(const ProofId &proofid, Callable &&func) const
boost::multi_index_container< Node, bmi::indexed_by< bmi::hashed_unique< bmi::member< Node, NodeId, &Node::nodeid > >, bmi::ordered_non_unique< bmi::tag< next_request_time >, bmi::composite_key< Node, bmi::member< Node, PeerId, &Node::peerid >, bmi::member< Node, SteadyMilliseconds, &Node::nextRequestTime > > > > > NodeSet
uint32_t getTotalPeersScore() const
bool latchAvaproofsSent(NodeId nodeid)
Flag that a node did send its compact proofs.
bool registerProof(const ProofRef &proof, RegistrationMode mode=RegistrationMode::DEFAULT)
bool addNode(NodeId nodeid, const ProofId &proofid)
Node API.
uint64_t getSlotCount() const
static constexpr int SELECT_PEER_MAX_RETRY
ProofIdSet m_unbroadcast_proofids
Track proof ids to broadcast.
bool loadPeersFromFile(const fs::path &dumpPath, std::unordered_set< ProofRef, SaltedProofHasher > &registeredProofs)
RejectionMode
Rejection mode.
void addUnbroadcastProof(const ProofId &proofid)
Proof broadcast API.
std::unordered_set< ProofRef, SaltedProofHasher > updatedBlockTip()
Update the peer set when a new block is connected.
void removeUnbroadcastProof(const ProofId &proofid)
const ProofRadixTree & getShareableProofsSnapshot() const
bool isBoundToPeer(const ProofId &proofid) const
boost::multi_index_container< RemoteProof, bmi::indexed_by< bmi::hashed_unique< bmi::composite_key< RemoteProof, bmi::member< RemoteProof, ProofId, &RemoteProof::proofid >, bmi::member< RemoteProof, NodeId, &RemoteProof::nodeid > >, bmi::composite_key_hash< SaltedProofIdHasher, boost::hash< NodeId > > >, bmi::hashed_non_unique< bmi::tag< by_proofid >, bmi::member< RemoteProof, ProofId, &RemoteProof::proofid >, SaltedProofIdHasher >, bmi::hashed_non_unique< bmi::tag< by_nodeid >, bmi::member< RemoteProof, NodeId, &RemoteProof::nodeid > >, bmi::ordered_non_unique< bmi::tag< by_lastUpdate >, bmi::composite_key< RemoteProof, bmi::member< RemoteProof, NodeId, &RemoteProof::nodeid >, bmi::member< RemoteProof, std::chrono::seconds, &RemoteProof::lastUpdate > > > > > RemoteProofSet
size_t getPendingNodeCount() const
const ProofPool & getImmatureProofPool() const
ProofRadixTree shareableProofs
bool saveRemoteProof(const ProofId &proofid, const NodeId nodeid, const bool present)
CRollingBloomFilter invalidProofs
Filter for proofs that are consensus-invalid or were recently invalidated by avalanche (finalized rej...
uint64_t compact()
Trigger maintenance of internal data structures.
PeerManager(const Amount &stakeUtxoDustThresholdIn, ChainstateManager &chainmanIn, const ProofRef &localProofIn=ProofRef())
std::vector< Slot > slots
uint32_t totalPeersScore
Quorum management.
void forEachPeer(Callable &&func) const
void setInvalid(const ProofId &proofid)
void forEachNode(const Peer &peer, Callable &&func) const
const Amount & getStakeUtxoDustThreshold() const
void forEachFlakyProof(Callable &&func) const
bool isFlaky(const ProofId &proofid) const
ChainstateManager & chainman
bool isInvalid(const ProofId &proofid) const
std::unordered_set< ProofId, SaltedProofIdHasher > manualFlakyProofids
bool removePeer(const PeerId peerid)
Remove an existing peer.
bool isImmature(const ProofId &proofid) const
bool addOrUpdateNode(const PeerSet::iterator &it, NodeId nodeid)
bool rejectProof(const ProofId &proofid, RejectionMode mode=RejectionMode::DEFAULT)
RegistrationMode
Registration mode.
ProofPool conflictingProofPool
const ProofPool & getConflictingProofPool() const
static constexpr size_t MAX_REMOTE_PROOFS
bool setFlaky(const ProofId &proofid)
std::atomic< bool > needMoreNodes
Flag indicating that we failed to select a node and need to expand our node set.
PeerId selectPeer() const
Randomly select a peer to poll.
boost::multi_index_container< Peer, bmi::indexed_by< bmi::hashed_unique< bmi::member< Peer, PeerId, &Peer::peerid > >, bmi::hashed_unique< bmi::tag< by_proofid >, proof_index, SaltedProofIdHasher >, bmi::ordered_non_unique< bmi::tag< by_score >, score_index, std::greater< uint32_t > > > > PeerSet
Several nodes can make an avalanche peer.
void updateAvailabilityScores(const double decayFactor, Callable &&getNodeAvailabilityScore)
auto getUnbroadcastProofs() const
bool isInConflictingPool(const ProofId &proofid) const
static constexpr int SELECT_NODE_MAX_RETRY
void cleanupDanglingProofs(std::unordered_set< ProofRef, SaltedProofHasher > &registeredProofs)
ProofRef getProof(const ProofId &proofid) const
bool registerProof(const ProofRef &proof, ProofRegistrationState &registrationState, RegistrationMode mode=RegistrationMode::DEFAULT)
bool removeNodeFromPeer(const PeerSet::iterator &it, uint32_t count=1)
bool updateNextPossibleConflictTime(PeerId peerid, const std::chrono::seconds &nextTime)
Proof and Peer related API.
void moveToConflictingPool(const ProofContainer &proofs)
Map a proof to each utxo.
Definition proofpool.h:57
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition fs.h:30
ProofRegistrationResult
static constexpr uint32_t AVALANCHE_MAX_IMMATURE_PROOFS
Maximum number of immature proofs the peer manager will accept from the network.
Definition peermanager.h:44
std::unordered_set< ProofId, SaltedProofIdHasher > ProofIdSet
Definition proofpool.h:52
PeerId selectPeerImpl(const std::vector< Slot > &slots, const uint64_t slot, const uint64_t max)
Internal methods that are exposed for testing purposes.
RCUPtr< const Proof > ProofRef
Definition proof.h:185
Definition init.h:28
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition rcu.h:259
int64_t NodeId
Definition nodeid.h:10
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
SteadyMilliseconds nextRequestTime
Definition node.h:23
std::chrono::seconds registration_time
Definition peermanager.h:93
std::chrono::seconds nextPossibleConflictTime
Definition peermanager.h:94
uint32_t node_count
Definition peermanager.h:87
double availabilityScore
Definition peermanager.h:96
static constexpr auto DANGLING_TIMEOUT
Consider dropping the peer if no node is attached after this timeout expired.
const ProofId & getProofId() const
uint32_t getScore() const
Peer(PeerId peerid_, ProofRef proof_, std::chrono::seconds nextPossibleConflictTime_)
PendingNode(ProofId proofid_, NodeId nodeid_)
std::chrono::seconds lastUpdate
Slot(uint64_t startIn, uint32_t scoreIn, PeerId peeridIn)
Definition peermanager.h:59
Slot withPeerId(PeerId peeridIn) const
Definition peermanager.h:68
uint32_t getScore() const
Definition peermanager.h:74
bool follows(uint64_t slot) const
Definition peermanager.h:81
Slot withScore(uint64_t scoreIn) const
Definition peermanager.h:65
Slot withStart(uint64_t startIn) const
Definition peermanager.h:62
uint64_t getStop() const
Definition peermanager.h:73
uint64_t getStart() const
Definition peermanager.h:72
PeerId getPeerId() const
Definition peermanager.h:75
bool precedes(uint64_t slot) const
Definition peermanager.h:80
bool contains(uint64_t slot) const
Definition peermanager.h:77
result_type operator()(const Peer &p) const
result_type operator()(const Peer &p) const
static int count
Definition tests.c:31
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition time.cpp:109
std::chrono::time_point< std::chrono::steady_clock, std::chrono::milliseconds > SteadyMilliseconds
Definition time.h:31