19 auto &pview =
peers.get<by_proofid>();
20 auto it = pview.find(proofid);
21 if (it == pview.end()) {
36 const PeerId peerid = it->peerid;
38 auto nit =
nodes.find(nodeid);
39 if (nit ==
nodes.end()) {
40 if (!
nodes.emplace(nodeid, peerid).second) {
44 const PeerId oldpeerid = nit->peerid;
45 if (!
nodes.modify(nit, [&](
Node &n) { n.peerid = peerid; })) {
75 slots.emplace_back(start, score, it->peerid);
89 auto it =
nodes.find(nodeid);
90 if (it ==
nodes.end()) {
94 const PeerId peerid = it->peerid;
109 if (it ==
peers.end()) {
113 assert(count <= it->node_count);
119 const uint32_t new_count = it->node_count -
count;
120 if (!
peers.modify(it, [&](
Peer &p) { p.node_count = new_count; })) {
131 const size_t i = it->index;
136 if (i + 1 ==
slots.size()) {
148 auto it =
nodes.find(nodeid);
149 if (it ==
nodes.end()) {
157 auto it =
nodes.find(nodeid);
158 if (it ==
nodes.end()) {
162 return !it->avaproofsSent &&
171 PeerId peerid,
const std::chrono::seconds &nextTime) {
172 auto it =
peers.find(peerid);
173 if (it ==
peers.end()) {
184 return it->nextPossibleConflictTime == nextTime;
188 auto it =
peers.find(peerid);
189 if (it ==
peers.end()) {
199 template <
typename ProofContainer>
201 auto &peersView =
peers.get<by_proofid>();
202 for (
const ProofRef &proof : proofs) {
203 auto it = peersView.find(proof->getId());
204 if (it != peersView.end()) {
217 const ProofId &proofid = proof->getId();
220 const std::string &message) {
221 return registrationState.
Invalid(
232 "proof-already-registered");
264 "utxo-missing-or-spent");
271 auto now = GetTime<std::chrono::seconds>();
272 auto nextCooldownTimePoint =
274 "-avalancheconflictingproofcooldown",
279 case ProofPool::AddProofStatus::REJECTED: {
281 auto bestPossibleConflictTime = std::chrono::seconds(0);
282 auto &pview =
peers.get<by_proofid>();
283 for (
auto &conflictingProof : conflictingProofs) {
284 auto it = pview.find(conflictingProof->getId());
285 assert(it != pview.end());
288 bestPossibleConflictTime = std::max(
289 bestPossibleConflictTime, it->nextPossibleConflictTime);
292 nextCooldownTimePoint);
295 if (bestPossibleConflictTime > now) {
299 "cooldown-not-elapsed");
315 ProofPool::AddProofStatus::REJECTED
319 "conflicting-utxos");
329 assert(status == ProofPool::AddProofStatus::SUCCEED);
333 case ProofPool::AddProofStatus::DUPLICATED:
336 "proof-already-registered");
337 case ProofPool::AddProofStatus::SUCCEED:
351 auto inserted =
peers.emplace(peerid, proof, nextCooldownTimePoint);
355 assert(insertedRadixTree);
361 auto &pendingNodesView =
pendingNodes.get<by_proofid>();
362 auto range = pendingNodesView.equal_range(proofid);
367 std::vector<NodeId> nodeids;
368 nodeids.reserve(std::distance(range.first, range.second));
369 std::transform(range.first, range.second, std::back_inserter(nodeids),
372 for (
const NodeId &nodeid : nodeids) {
400 auto &pview =
peers.get<by_proofid>();
401 auto it = pview.find(proofid);
402 assert(it != pview.end());
414 if (!conflictingProof) {
430 const auto now = GetTime<std::chrono::seconds>();
432 std::vector<ProofId> newlyDanglingProofIds;
436 if ((!localProof || peer.getProofId() != localProof->getId()) &&
437 peer.node_count == 0 &&
439 newlyDanglingProofIds.push_back(peer.getProofId());
443 for (
const ProofId &proofid : newlyDanglingProofIds) {
448 "Proof dropped for dangling too long (no connected node): %s\n",
470 auto it = nview.lower_bound(boost::make_tuple(p,
TimePoint()));
471 if (it != nview.end() && it->peerid == p &&
472 it->nextRequestTime <= std::chrono::steady_clock::now()) {
484 std::vector<ProofId> invalidProofIds;
485 std::vector<ProofRef> newImmatures;
490 for (
const auto &p :
peers) {
494 newImmatures.push_back(p.proof);
496 invalidProofIds.push_back(p.getProofId());
504 for (
const ProofId &invalidProofId : invalidProofIds) {
510 for (
auto &p : newImmatures) {
514 return registeredProofs;
537 auto &pview =
peers.get<by_proofid>();
538 return pview.find(proofid) != pview.end();
550 auto it =
peers.find(peerid);
551 if (it ==
peers.end()) {
561 auto range = nview.equal_range(peerid);
562 for (
auto &nit = range.first; nit != range.second; ++nit) {
569 nview.erase(nview.lower_bound(boost::make_tuple(peerid,
TimePoint())),
570 nview.upper_bound(boost::make_tuple(
571 peerid, std::chrono::steady_clock::now())));
577 assert(removed !=
nullptr);
611 std::vector<Slot> newslots;
612 newslots.reserve(
peers.size());
614 uint64_t prevStop = 0;
616 for (
auto it =
peers.begin(); it !=
peers.end(); it++) {
617 if (it->node_count == 0) {
621 newslots.emplace_back(prevStop, it->getScore(), it->peerid);
622 prevStop =
slots[i].getStop();
623 if (!
peers.modify(it, [&](
Peer &p) { p.index = i++; })) {
628 slots = std::move(newslots);
630 const uint64_t saved =
slotCount - prevStop;
638 uint64_t prevStop = 0;
639 uint32_t scoreFromSlots = 0;
640 for (
size_t i = 0; i <
slots.size(); i++) {
657 if (it ==
peers.end() || it->index != i) {
662 scoreFromSlots +=
slots[i].getScore();
670 uint32_t scoreFromAllPeers = 0;
671 uint32_t scoreFromPeersWithNodes = 0;
673 std::unordered_set<COutPoint, SaltedOutpointHasher> peersUtxos;
674 for (
const auto &p :
peers) {
676 scoreFromAllPeers += p.getScore();
684 for (
const auto &ss : p.proof->getStakes()) {
685 const COutPoint &outpoint = ss.getStake().getUTXO();
692 if (proof != p.proof) {
697 if (!peersUtxos.emplace(outpoint).second) {
704 const auto count_nodes = [&]() {
708 nview.lower_bound(boost::make_tuple(p.peerid,
TimePoint()));
710 nview.upper_bound(boost::make_tuple(p.peerid + 1,
TimePoint()));
712 for (
auto it = begin; it != end; ++it) {
719 if (p.node_count != count_nodes()) {
724 if (p.node_count == 0) {
728 scoreFromPeersWithNodes += p.getScore();
730 if (p.index >=
slots.size() ||
slots[p.index].getPeerId() != p.peerid) {
735 if (
slots[p.index].getScore() != p.getScore()) {
766 const uint64_t max) {
769 size_t begin = 0, end = slots.size();
770 uint64_t bottom = 0, top = max;
773 while ((end - begin) > 8) {
775 if (slot < bottom || slot >= top) {
780 size_t i = begin + ((slot - bottom) * (end - begin) / (top - bottom));
781 assert(begin <= i && i < end);
784 if (slots[i].contains(slot)) {
785 return slots[i].getPeerId();
789 if (slots[i].precedes(slot)) {
795 bottom = slots[begin].getStart();
800 if (slots[i].follows(slot)) {
802 top = slots[end].getStart();
811 for (
size_t i = begin; i < end; i++) {
813 if (slots[i].contains(slot)) {
814 return slots[i].getPeerId();
static constexpr PeerId NO_PEER
std::chrono::time_point< std::chrono::steady_clock > TimePoint
static constexpr size_t AVALANCHE_DEFAULT_CONFLICTING_PROOF_COOLDOWN
Conflicting proofs cooldown time default value in seconds.
RecursiveMutex cs_main
Global state.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
An outpoint - a combination of a transaction hash and an index n into its vout.
bool contains(const std::vector< uint8_t > &vKey) const
void insert(const std::vector< uint8_t > &vKey)
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
uint32_t connectedPeersScore
bool removeNode(NodeId nodeid)
bool setFinalized(PeerId peerid)
Latch on that this peer has a finalized proof.
void cleanupDanglingProofs(const ProofRef &localProof)
bool addNodeToPeer(const PeerSet::iterator &it)
bool exists(const ProofId &proofid) const
bool updateNextRequestTime(NodeId nodeid, TimePoint timeout)
PendingNodeSet pendingNodes
bool verify() const
Perform consistency check on internal data structures.
bool forPeer(const ProofId &proofid, Callable &&func) const
bool latchAvaproofsSent(NodeId nodeid)
Flag that a node did send its compact proofs.
bool addNode(NodeId nodeid, const ProofId &proofid)
Node API.
static constexpr int SELECT_PEER_MAX_RETRY
ProofIdSet m_unbroadcast_proofids
Track proof ids to broadcast.
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)
bool isBoundToPeer(const ProofId &proofid) const
ProofRadixTree shareableProofs
uint64_t compact()
Trigger maintenance of internal data structures.
std::vector< Slot > slots
uint32_t totalPeersScore
Quorum management.
ChainstateManager & chainman
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)
ProofPool immatureProofPool
Amount stakeUtxoDustThreshold
RegistrationMode
Registration mode.
ProofPool conflictingProofPool
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.
bool isInConflictingPool(const ProofId &proofid) const
static constexpr int SELECT_NODE_MAX_RETRY
ProofRef getProof(const ProofId &proofid) const
bool registerProof(const ProofRef &proof, ProofRegistrationState ®istrationState, 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)
CRollingBloomFilter danglingProofIds
Remember the last proofs that have been evicted because they had no node attached.
AddProofStatus addProofIfPreferred(const ProofRef &proof, ConflictingProofSet &conflictingProofs)
Attempt to add a proof to the pool.
AddProofStatus addProofIfNoConflict(const ProofRef &proof, ConflictingProofSet &conflictingProofs)
Attempt to add a proof to the pool, and fail if there is a conflict on any UTXO.
size_t countProofs() const
bool removeProof(ProofId proofid)
ProofRef getProof(const ProofId &proofid) const
std::set< ProofRef, ConflictingProofComparator > ConflictingProofSet
ProofRef getLowestScoreProof() const
std::unordered_set< ProofRef, SaltedProofHasher > rescan(PeerManager &peerManager)
std::string ToString() const
#define LogPrint(category,...)
static constexpr uint32_t AVALANCHE_MAX_IMMATURE_PROOFS
Maximum number of immature proofs the peer manager will accept from the network.
static bool isImmatureState(const ProofValidationState &state)
PeerId selectPeerImpl(const std::vector< Slot > &slots, const uint64_t slot, const uint64_t max)
Internal methods that are exposed for testing purposes.
static constexpr NodeId NO_NODE
Special NodeId that represent no node.
uint64_t GetRand(uint64_t nMax) noexcept
Generate a uniform random integer in the range [0..range).
RCUPtr< T > get(const KeyType &key)
Get the value corresponding to a key.
RCUPtr< T > remove(const KeyType &key)
Remove an element from the tree.
bool forEachLeaf(Callable &&func) const
bool insert(const RCUPtr< T > &value)
Insert a value into the tree.
Facility for using an uint256 as a radix tree key.
TimePoint nextRequestTime
std::chrono::seconds nextPossibleConflictTime
static constexpr auto DANGLING_TIMEOUT
Consider dropping the peer if no node is attached after this timeout expired.
uint32_t getScore() const
uint64_t getStart() const
#define WITH_LOCK(cs, code)
Run code while locking a mutex.