Bitcoin ABC  0.26.3
P2P Digital Currency
peermanager.cpp
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 
6 
7 #include <avalanche/avalanche.h>
8 #include <avalanche/delegation.h>
9 #include <avalanche/validation.h>
10 #include <random.h>
11 #include <scheduler.h>
12 #include <validation.h> // For ChainstateManager
13 
14 #include <algorithm>
15 #include <cassert>
16 
17 namespace avalanche {
18 bool PeerManager::addNode(NodeId nodeid, const ProofId &proofid) {
19  auto &pview = peers.get<by_proofid>();
20  auto it = pview.find(proofid);
21  if (it == pview.end()) {
22  // If the node exists, it is actually updating its proof to an unknown
23  // one. In this case we need to remove it so it is not both active and
24  // pending at the same time.
25  removeNode(nodeid);
26  pendingNodes.emplace(proofid, nodeid);
27  return false;
28  }
29 
30  return addOrUpdateNode(peers.project<0>(it), nodeid);
31 }
32 
33 bool PeerManager::addOrUpdateNode(const PeerSet::iterator &it, NodeId nodeid) {
34  assert(it != peers.end());
35 
36  const PeerId peerid = it->peerid;
37 
38  auto nit = nodes.find(nodeid);
39  if (nit == nodes.end()) {
40  if (!nodes.emplace(nodeid, peerid).second) {
41  return false;
42  }
43  } else {
44  const PeerId oldpeerid = nit->peerid;
45  if (!nodes.modify(nit, [&](Node &n) { n.peerid = peerid; })) {
46  return false;
47  }
48 
49  // We actually have this node already, we need to update it.
50  bool success = removeNodeFromPeer(peers.find(oldpeerid));
51  assert(success);
52  }
53 
54  bool success = addNodeToPeer(it);
55  assert(success);
56 
57  // If the added node was in the pending set, remove it
58  pendingNodes.get<by_nodeid>().erase(nodeid);
59 
60  return true;
61 }
62 
63 bool PeerManager::addNodeToPeer(const PeerSet::iterator &it) {
64  assert(it != peers.end());
65  return peers.modify(it, [&](Peer &p) {
66  if (p.node_count++ > 0) {
67  // We are done.
68  return;
69  }
70 
71  // We need to allocate this peer.
72  p.index = uint32_t(slots.size());
73  const uint32_t score = p.getScore();
74  const uint64_t start = slotCount;
75  slots.emplace_back(start, score, it->peerid);
76  slotCount = start + score;
77 
78  // Add to our allocated score when we allocate a new peer in the slots
79  connectedPeersScore += score;
80  });
81 }
82 
84  if (pendingNodes.get<by_nodeid>().erase(nodeid) > 0) {
85  // If this was a pending node, there is nothing else to do.
86  return true;
87  }
88 
89  auto it = nodes.find(nodeid);
90  if (it == nodes.end()) {
91  return false;
92  }
93 
94  const PeerId peerid = it->peerid;
95  nodes.erase(it);
96 
97  // Keep the track of the reference count.
98  bool success = removeNodeFromPeer(peers.find(peerid));
99  assert(success);
100 
101  return true;
102 }
103 
104 bool PeerManager::removeNodeFromPeer(const PeerSet::iterator &it,
105  uint32_t count) {
106  // It is possible for nodes to be dangling. If there was an inflight query
107  // when the peer gets removed, the node was not erased. In this case there
108  // is nothing to do.
109  if (it == peers.end()) {
110  return true;
111  }
112 
113  assert(count <= it->node_count);
114  if (count == 0) {
115  // This is a NOOP.
116  return false;
117  }
118 
119  const uint32_t new_count = it->node_count - count;
120  if (!peers.modify(it, [&](Peer &p) { p.node_count = new_count; })) {
121  return false;
122  }
123 
124  if (new_count > 0) {
125  // We are done.
126  return true;
127  }
128 
129  // There are no more nodes left, we need to clean up. Subtract allocated
130  // score and remove from slots.
131  const size_t i = it->index;
132  assert(i < slots.size());
133  assert(connectedPeersScore >= slots[i].getScore());
134  connectedPeersScore -= slots[i].getScore();
135 
136  if (i + 1 == slots.size()) {
137  slots.pop_back();
138  slotCount = slots.empty() ? 0 : slots.back().getStop();
139  } else {
140  fragmentation += slots[i].getScore();
141  slots[i] = slots[i].withPeerId(NO_PEER);
142  }
143 
144  return true;
145 }
146 
148  auto it = nodes.find(nodeid);
149  if (it == nodes.end()) {
150  return false;
151  }
152 
153  return nodes.modify(it, [&](Node &n) { n.nextRequestTime = timeout; });
154 }
155 
157  auto it = nodes.find(nodeid);
158  if (it == nodes.end()) {
159  return false;
160  }
161 
162  return !it->avaproofsSent &&
163  nodes.modify(it, [&](Node &n) { n.avaproofsSent = true; });
164 }
165 
166 static bool isImmatureState(const ProofValidationState &state) {
168 }
169 
171  PeerId peerid, const std::chrono::seconds &nextTime) {
172  auto it = peers.find(peerid);
173  if (it == peers.end()) {
174  // No such peer
175  return false;
176  }
177 
178  // Make sure we don't move the time in the past.
179  peers.modify(it, [&](Peer &p) {
181  std::max(p.nextPossibleConflictTime, nextTime);
182  });
183 
184  return it->nextPossibleConflictTime == nextTime;
185 }
186 
188  auto it = peers.find(peerid);
189  if (it == peers.end()) {
190  // No such peer
191  return false;
192  }
193 
194  peers.modify(it, [&](Peer &p) { p.hasFinalized = true; });
195 
196  return true;
197 }
198 
199 template <typename ProofContainer>
200 void PeerManager::moveToConflictingPool(const ProofContainer &proofs) {
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()) {
205  removePeer(it->peerid);
206  }
207 
209  }
210 }
211 
213  ProofRegistrationState &registrationState,
214  RegistrationMode mode) {
215  assert(proof);
216 
217  const ProofId &proofid = proof->getId();
218 
219  auto invalidate = [&](ProofRegistrationResult result,
220  const std::string &message) {
221  return registrationState.Invalid(
222  result, message, strprintf("proofid: %s", proofid.ToString()));
223  };
224 
225  if ((mode != RegistrationMode::FORCE_ACCEPT ||
226  !isInConflictingPool(proofid)) &&
227  exists(proofid)) {
228  // In default mode, we expect the proof to be unknown, i.e. in none of
229  // the pools.
230  // In forced accept mode, the proof can be in the conflicting pool.
232  "proof-already-registered");
233  }
234 
235  if (danglingProofIds.contains(proofid) &&
236  pendingNodes.count(proofid) == 0) {
237  // Don't attempt to register a proof that we already evicted because it
238  // was dangling, but rather attempt to retrieve an associated node.
239  needMoreNodes = true;
240  return invalidate(ProofRegistrationResult::DANGLING, "dangling-proof");
241  }
242 
243  // Check the proof's validity.
244  ProofValidationState validationState;
245  if (!WITH_LOCK(cs_main, return proof->verify(stakeUtxoDustThreshold,
246  chainman, validationState))) {
247  if (isImmatureState(validationState)) {
251  // Adding this proof exceeds the immature pool limit, so evict
252  // the lowest scoring proof.
255  }
256 
257  return invalidate(ProofRegistrationResult::IMMATURE,
258  "immature-proof");
259  }
260 
261  if (validationState.GetResult() ==
263  return invalidate(ProofRegistrationResult::MISSING_UTXO,
264  "utxo-missing-or-spent");
265  }
266 
267  // Reject invalid proof.
268  return invalidate(ProofRegistrationResult::INVALID, "invalid-proof");
269  }
270 
271  auto now = GetTime<std::chrono::seconds>();
272  auto nextCooldownTimePoint =
273  now + std::chrono::seconds(gArgs.GetIntArg(
274  "-avalancheconflictingproofcooldown",
276 
277  ProofPool::ConflictingProofSet conflictingProofs;
278  switch (validProofPool.addProofIfNoConflict(proof, conflictingProofs)) {
279  case ProofPool::AddProofStatus::REJECTED: {
280  if (mode != RegistrationMode::FORCE_ACCEPT) {
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());
286 
287  // Search the most recent time over the peers
288  bestPossibleConflictTime = std::max(
289  bestPossibleConflictTime, it->nextPossibleConflictTime);
290 
292  nextCooldownTimePoint);
293  }
294 
295  if (bestPossibleConflictTime > now) {
296  // Cooldown not elapsed, reject the proof.
297  return invalidate(
299  "cooldown-not-elapsed");
300  }
301 
302  // Give the proof a chance to replace the conflicting ones.
303  if (validProofPool.addProofIfPreferred(proof)) {
304  // If we have overridden other proofs due to conflict,
305  // remove the peers and attempt to move them to the
306  // conflicting pool.
307  moveToConflictingPool(conflictingProofs);
308 
309  // Replacement is successful, continue to peer creation
310  break;
311  }
312 
313  // Not the preferred proof, or replacement is not enabled
315  ProofPool::AddProofStatus::REJECTED
317  "rejected-proof")
319  "conflicting-utxos");
320  }
321 
323 
324  // Move the conflicting proofs from the valid pool to the
325  // conflicting pool
326  moveToConflictingPool(conflictingProofs);
327 
328  auto status = validProofPool.addProofIfNoConflict(proof);
329  assert(status == ProofPool::AddProofStatus::SUCCEED);
330 
331  break;
332  }
333  case ProofPool::AddProofStatus::DUPLICATED:
334  // If the proof was already in the pool, don't duplicate the peer.
336  "proof-already-registered");
337  case ProofPool::AddProofStatus::SUCCEED:
338  break;
339 
340  // No default case, so the compiler can warn about missing cases
341  }
342 
343  // At this stage we are going to create a peer so the proof should never
344  // exist in the conflicting pool, but use belt and suspenders.
346 
347  // New peer means new peerid!
348  const PeerId peerid = nextPeerId++;
349 
350  // We have no peer for this proof, time to create it.
351  auto inserted = peers.emplace(peerid, proof, nextCooldownTimePoint);
352  assert(inserted.second);
353 
354  auto insertedRadixTree = shareableProofs.insert(proof);
355  assert(insertedRadixTree);
356 
357  // Add to our registered score when adding to the peer list
358  totalPeersScore += proof->getScore();
359 
360  // If there are nodes waiting for this proof, add them
361  auto &pendingNodesView = pendingNodes.get<by_proofid>();
362  auto range = pendingNodesView.equal_range(proofid);
363 
364  // We want to update the nodes then remove them from the pending set. That
365  // will invalidate the range iterators, so we need to save the node ids
366  // first before we can loop over them.
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),
370  [](const PendingNode &n) { return n.nodeid; });
371 
372  for (const NodeId &nodeid : nodeids) {
373  addOrUpdateNode(inserted.first, nodeid);
374  }
375 
376  return true;
377 }
378 
379 bool PeerManager::rejectProof(const ProofId &proofid, RejectionMode mode) {
380  if (!exists(proofid)) {
381  return false;
382  }
383 
384  if (immatureProofPool.removeProof(proofid)) {
385  return true;
386  }
387 
388  if (mode == RejectionMode::DEFAULT &&
389  conflictingProofPool.getProof(proofid)) {
390  // In default mode we keep the proof in the conflicting pool
391  return true;
392  }
393 
394  if (mode == RejectionMode::INVALIDATE &&
396  // In invalidate mode we remove the proof completely
397  return true;
398  }
399 
400  auto &pview = peers.get<by_proofid>();
401  auto it = pview.find(proofid);
402  assert(it != pview.end());
403 
404  const ProofRef proof = it->proof;
405 
406  if (!removePeer(it->peerid)) {
407  return false;
408  }
409 
410  // If there was conflicting proofs, attempt to pull them back
411  for (const SignedStake &ss : proof->getStakes()) {
412  const ProofRef conflictingProof =
413  conflictingProofPool.getProof(ss.getStake().getUTXO());
414  if (!conflictingProof) {
415  continue;
416  }
417 
418  conflictingProofPool.removeProof(conflictingProof->getId());
419  registerProof(conflictingProof);
420  }
421 
422  if (mode == RejectionMode::DEFAULT) {
424  }
425 
426  return true;
427 }
428 
430  const auto now = GetTime<std::chrono::seconds>();
431 
432  std::vector<ProofId> newlyDanglingProofIds;
433  for (const Peer &peer : peers) {
434  // If the peer is not our local proof, has been registered for some
435  // time and has no node attached, discard it.
436  if ((!localProof || peer.getProofId() != localProof->getId()) &&
437  peer.node_count == 0 &&
438  (peer.registration_time + Peer::DANGLING_TIMEOUT) <= now) {
439  newlyDanglingProofIds.push_back(peer.getProofId());
440  }
441  }
442 
443  for (const ProofId &proofid : newlyDanglingProofIds) {
445  danglingProofIds.insert(proofid);
446  LogPrint(
448  "Proof dropped for dangling too long (no connected node): %s\n",
449  proofid.GetHex());
450  }
451 
452  // If we have dangling proof, this is a good indicator that we need to
453  // request more nodes from our peers.
454  needMoreNodes = !newlyDanglingProofIds.empty();
455 }
456 
458  for (int retry = 0; retry < SELECT_NODE_MAX_RETRY; retry++) {
459  const PeerId p = selectPeer();
460 
461  // If we cannot find a peer, it may be due to the fact that it is
462  // unlikely due to high fragmentation, so compact and retry.
463  if (p == NO_PEER) {
464  compact();
465  continue;
466  }
467 
468  // See if that peer has an available node.
469  auto &nview = nodes.get<next_request_time>();
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()) {
473  return it->nodeid;
474  }
475  }
476 
477  // We failed to find a node to query, flag this so we can request more
478  needMoreNodes = true;
479 
480  return NO_NODE;
481 }
482 
483 std::unordered_set<ProofRef, SaltedProofHasher> PeerManager::updatedBlockTip() {
484  std::vector<ProofId> invalidProofIds;
485  std::vector<ProofRef> newImmatures;
486 
487  {
488  LOCK(cs_main);
489 
490  for (const auto &p : peers) {
491  ProofValidationState state;
492  if (!p.proof->verify(stakeUtxoDustThreshold, chainman, state)) {
493  if (isImmatureState(state)) {
494  newImmatures.push_back(p.proof);
495  }
496  invalidProofIds.push_back(p.getProofId());
497  }
498  }
499  }
500 
501  // Remove the invalid proofs before the immature rescan. This makes it
502  // possible to pull back proofs with utxos that conflicted with these
503  // invalid proofs.
504  for (const ProofId &invalidProofId : invalidProofIds) {
505  rejectProof(invalidProofId, RejectionMode::INVALIDATE);
506  }
507 
508  auto registeredProofs = immatureProofPool.rescan(*this);
509 
510  for (auto &p : newImmatures) {
512  }
513 
514  return registeredProofs;
515 }
516 
517 ProofRef PeerManager::getProof(const ProofId &proofid) const {
518  ProofRef proof;
519 
520  forPeer(proofid, [&](const Peer &p) {
521  proof = p.proof;
522  return true;
523  });
524 
525  if (!proof) {
526  proof = conflictingProofPool.getProof(proofid);
527  }
528 
529  if (!proof) {
530  proof = immatureProofPool.getProof(proofid);
531  }
532 
533  return proof;
534 }
535 
536 bool PeerManager::isBoundToPeer(const ProofId &proofid) const {
537  auto &pview = peers.get<by_proofid>();
538  return pview.find(proofid) != pview.end();
539 }
540 
541 bool PeerManager::isImmature(const ProofId &proofid) const {
542  return immatureProofPool.getProof(proofid) != nullptr;
543 }
544 
545 bool PeerManager::isInConflictingPool(const ProofId &proofid) const {
546  return conflictingProofPool.getProof(proofid) != nullptr;
547 }
548 
549 bool PeerManager::removePeer(const PeerId peerid) {
550  auto it = peers.find(peerid);
551  if (it == peers.end()) {
552  return false;
553  }
554 
555  // Remove all nodes from this peer.
556  removeNodeFromPeer(it, it->node_count);
557 
558  auto &nview = nodes.get<next_request_time>();
559 
560  // Add the nodes to the pending set
561  auto range = nview.equal_range(peerid);
562  for (auto &nit = range.first; nit != range.second; ++nit) {
563  pendingNodes.emplace(it->getProofId(), nit->nodeid);
564  };
565 
566  // Remove nodes associated with this peer, unless their timeout is still
567  // active. This ensure that we don't overquery them in case they are
568  // subsequently added to another peer.
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())));
572 
573  // Release UTXOs attached to this proof.
574  validProofPool.removeProof(it->getProofId());
575 
576  auto removed = shareableProofs.remove(Uint256RadixKey(it->getProofId()));
577  assert(removed != nullptr);
578 
579  m_unbroadcast_proofids.erase(it->getProofId());
580 
581  // Remove the peer from the PeerSet and remove its score from the registered
582  // score total.
583  assert(totalPeersScore >= it->getScore());
584  totalPeersScore -= it->getScore();
585  peers.erase(it);
586  return true;
587 }
588 
590  if (slots.empty() || slotCount == 0) {
591  return NO_PEER;
592  }
593 
594  const uint64_t max = slotCount;
595  for (int retry = 0; retry < SELECT_PEER_MAX_RETRY; retry++) {
596  size_t i = selectPeerImpl(slots, GetRand(max), max);
597  if (i != NO_PEER) {
598  return i;
599  }
600  }
601 
602  return NO_PEER;
603 }
604 
606  // There is nothing to compact.
607  if (fragmentation == 0) {
608  return 0;
609  }
610 
611  std::vector<Slot> newslots;
612  newslots.reserve(peers.size());
613 
614  uint64_t prevStop = 0;
615  uint32_t i = 0;
616  for (auto it = peers.begin(); it != peers.end(); it++) {
617  if (it->node_count == 0) {
618  continue;
619  }
620 
621  newslots.emplace_back(prevStop, it->getScore(), it->peerid);
622  prevStop = slots[i].getStop();
623  if (!peers.modify(it, [&](Peer &p) { p.index = i++; })) {
624  return 0;
625  }
626  }
627 
628  slots = std::move(newslots);
629 
630  const uint64_t saved = slotCount - prevStop;
631  slotCount = prevStop;
632  fragmentation = 0;
633 
634  return saved;
635 }
636 
637 bool PeerManager::verify() const {
638  uint64_t prevStop = 0;
639  uint32_t scoreFromSlots = 0;
640  for (size_t i = 0; i < slots.size(); i++) {
641  const Slot &s = slots[i];
642 
643  // Slots must be in correct order.
644  if (s.getStart() < prevStop) {
645  return false;
646  }
647 
648  prevStop = s.getStop();
649 
650  // If this is a dead slot, then nothing more needs to be checked.
651  if (s.getPeerId() == NO_PEER) {
652  continue;
653  }
654 
655  // We have a live slot, verify index.
656  auto it = peers.find(s.getPeerId());
657  if (it == peers.end() || it->index != i) {
658  return false;
659  }
660 
661  // Accumulate score across slots
662  scoreFromSlots += slots[i].getScore();
663  }
664 
665  // Score across slots must be the same as our allocated score
666  if (scoreFromSlots != connectedPeersScore) {
667  return false;
668  }
669 
670  uint32_t scoreFromAllPeers = 0;
671  uint32_t scoreFromPeersWithNodes = 0;
672 
673  std::unordered_set<COutPoint, SaltedOutpointHasher> peersUtxos;
674  for (const auto &p : peers) {
675  // Accumulate the score across peers to compare with total known score
676  scoreFromAllPeers += p.getScore();
677 
678  // A peer should have a proof attached
679  if (!p.proof) {
680  return false;
681  }
682 
683  // Check proof pool consistency
684  for (const auto &ss : p.proof->getStakes()) {
685  const COutPoint &outpoint = ss.getStake().getUTXO();
686  auto proof = validProofPool.getProof(outpoint);
687 
688  if (!proof) {
689  // Missing utxo
690  return false;
691  }
692  if (proof != p.proof) {
693  // Wrong proof
694  return false;
695  }
696 
697  if (!peersUtxos.emplace(outpoint).second) {
698  // Duplicated utxo
699  return false;
700  }
701  }
702 
703  // Count node attached to this peer.
704  const auto count_nodes = [&]() {
705  size_t count = 0;
706  auto &nview = nodes.get<next_request_time>();
707  auto begin =
708  nview.lower_bound(boost::make_tuple(p.peerid, TimePoint()));
709  auto end =
710  nview.upper_bound(boost::make_tuple(p.peerid + 1, TimePoint()));
711 
712  for (auto it = begin; it != end; ++it) {
713  count++;
714  }
715 
716  return count;
717  };
718 
719  if (p.node_count != count_nodes()) {
720  return false;
721  }
722 
723  // If there are no nodes attached to this peer, then we are done.
724  if (p.node_count == 0) {
725  continue;
726  }
727 
728  scoreFromPeersWithNodes += p.getScore();
729  // The index must point to a slot refering to this peer.
730  if (p.index >= slots.size() || slots[p.index].getPeerId() != p.peerid) {
731  return false;
732  }
733 
734  // If the score do not match, same thing.
735  if (slots[p.index].getScore() != p.getScore()) {
736  return false;
737  }
738 
739  // Check the proof is in the radix tree
740  if (shareableProofs.get(p.getProofId()) == nullptr) {
741  return false;
742  }
743  }
744 
745  // Check our accumulated scores against our registred and allocated scores
746  if (scoreFromAllPeers != totalPeersScore) {
747  return false;
748  }
749  if (scoreFromPeersWithNodes != connectedPeersScore) {
750  return false;
751  }
752 
753  // We checked the utxo consistency for all our peers utxos already, so if
754  // the pool size differs from the expected one there are dangling utxos.
755  if (validProofPool.size() != peersUtxos.size()) {
756  return false;
757  }
758 
759  // Check there is no dangling proof in the radix tree
761  return isBoundToPeer(pLeaf->getId());
762  });
763 }
764 
765 PeerId selectPeerImpl(const std::vector<Slot> &slots, const uint64_t slot,
766  const uint64_t max) {
767  assert(slot <= max);
768 
769  size_t begin = 0, end = slots.size();
770  uint64_t bottom = 0, top = max;
771 
772  // Try to find the slot using dichotomic search.
773  while ((end - begin) > 8) {
774  // The slot we picked in not allocated.
775  if (slot < bottom || slot >= top) {
776  return NO_PEER;
777  }
778 
779  // Guesstimate the position of the slot.
780  size_t i = begin + ((slot - bottom) * (end - begin) / (top - bottom));
781  assert(begin <= i && i < end);
782 
783  // We have a match.
784  if (slots[i].contains(slot)) {
785  return slots[i].getPeerId();
786  }
787 
788  // We undershooted.
789  if (slots[i].precedes(slot)) {
790  begin = i + 1;
791  if (begin >= end) {
792  return NO_PEER;
793  }
794 
795  bottom = slots[begin].getStart();
796  continue;
797  }
798 
799  // We overshooted.
800  if (slots[i].follows(slot)) {
801  end = i;
802  top = slots[end].getStart();
803  continue;
804  }
805 
806  // We have an unalocated slot.
807  return NO_PEER;
808  }
809 
810  // Enough of that nonsense, let fallback to linear search.
811  for (size_t i = begin; i < end; i++) {
812  // We have a match.
813  if (slots[i].contains(slot)) {
814  return slots[i].getPeerId();
815  }
816  }
817 
818  // We failed to find a slot, retry.
819  return NO_PEER;
820 }
821 
823  // The proof should be bound to a peer
824  if (isBoundToPeer(proofid)) {
825  m_unbroadcast_proofids.insert(proofid);
826  }
827 }
828 
830  m_unbroadcast_proofids.erase(proofid);
831 }
832 
833 } // namespace avalanche
static constexpr PeerId NO_PEER
Definition: node.h:15
std::chrono::time_point< std::chrono::steady_clock > TimePoint
Definition: node.h:17
uint32_t PeerId
Definition: node.h:14
static constexpr size_t AVALANCHE_DEFAULT_CONFLICTING_PROOF_COOLDOWN
Conflicting proofs cooldown time default value in seconds.
Definition: avalanche.h:28
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:111
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: system.cpp:593
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
bool contains(const std::vector< uint8_t > &vKey) const
Definition: bloom.cpp:275
void insert(const std::vector< uint8_t > &vKey)
Definition: bloom.cpp:236
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
Definition: validation.h:102
Result GetResult() const
Definition: validation.h:123
uint32_t connectedPeersScore
Definition: peermanager.h:238
bool removeNode(NodeId nodeid)
Definition: peermanager.cpp:83
bool setFinalized(PeerId peerid)
Latch on that this peer has a finalized proof.
void cleanupDanglingProofs(const ProofRef &localProof)
bool addNodeToPeer(const PeerSet::iterator &it)
Definition: peermanager.cpp:63
bool exists(const ProofId &proofid) const
Definition: peermanager.h:344
bool updateNextRequestTime(NodeId nodeid, TimePoint timeout)
PendingNodeSet pendingNodes
Definition: peermanager.h:215
bool verify() const
Perform consistency check on internal data structures.
bool forPeer(const ProofId &proofid, Callable &&func) const
Definition: peermanager.h:351
bool latchAvaproofsSent(NodeId nodeid)
Flag that a node did send its compact proofs.
bool addNode(NodeId nodeid, const ProofId &proofid)
Node API.
Definition: peermanager.cpp:18
static constexpr int SELECT_PEER_MAX_RETRY
Definition: peermanager.h:217
ProofIdSet m_unbroadcast_proofids
Track proof ids to broadcast.
Definition: peermanager.h:223
RejectionMode
Rejection mode.
Definition: peermanager.h:336
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
Definition: peermanager.h:181
uint64_t compact()
Trigger maintenance of internal data structures.
std::vector< Slot > slots
Definition: peermanager.h:154
uint32_t totalPeersScore
Quorum management.
Definition: peermanager.h:237
ChainstateManager & chainman
Definition: peermanager.h:242
bool removePeer(const PeerId peerid)
Remove an existing peer.
bool isImmature(const ProofId &proofid) const
bool addOrUpdateNode(const PeerSet::iterator &it, NodeId nodeid)
Definition: peermanager.cpp:33
bool rejectProof(const ProofId &proofid, RejectionMode mode=RejectionMode::DEFAULT)
ProofPool immatureProofPool
Definition: peermanager.h:178
RegistrationMode
Registration mode.
Definition: peermanager.h:313
ProofPool conflictingProofPool
Definition: peermanager.h:177
std::atomic< bool > needMoreNodes
Flag indicating that we failed to select a node and need to expand our node set.
Definition: peermanager.h:201
PeerId selectPeer() const
Randomly select a peer to poll.
bool isInConflictingPool(const ProofId &proofid) const
static constexpr int SELECT_NODE_MAX_RETRY
Definition: peermanager.h:218
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)
CRollingBloomFilter danglingProofIds
Remember the last proofs that have been evicted because they had no node attached.
Definition: peermanager.h:232
AddProofStatus addProofIfPreferred(const ProofRef &proof, ConflictingProofSet &conflictingProofs)
Attempt to add a proof to the pool.
Definition: proofpool.cpp:54
size_t size() const
Definition: proofpool.h:135
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.
Definition: proofpool.cpp:13
size_t countProofs() const
Definition: proofpool.cpp:129
bool removeProof(ProofId proofid)
Definition: proofpool.cpp:79
ProofRef getProof(const ProofId &proofid) const
Definition: proofpool.cpp:112
std::set< ProofRef, ConflictingProofComparator > ConflictingProofSet
Definition: proofpool.h:88
ProofRef getLowestScoreProof() const
Definition: proofpool.cpp:123
std::unordered_set< ProofRef, SaltedProofHasher > rescan(PeerManager &peerManager)
Definition: proofpool.cpp:86
std::string ToString() const
Definition: uint256.h:78
#define LogPrint(category,...)
Definition: logging.h:208
@ AVALANCHE
Definition: logging.h:61
ProofRegistrationResult
Definition: peermanager.h:136
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
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.
Definition: nodeid.h:15
int64_t NodeId
Definition: nodeid.h:10
uint64_t GetRand(uint64_t nMax) noexcept
Generate a uniform random integer in the range [0..range).
Definition: random.cpp:650
RCUPtr< T > get(const KeyType &key)
Get the value corresponding to a key.
Definition: radix.h:118
RCUPtr< T > remove(const KeyType &key)
Remove an element from the tree.
Definition: radix.h:181
bool forEachLeaf(Callable &&func) const
Definition: radix.h:144
bool insert(const RCUPtr< T > &value)
Insert a value into the tree.
Definition: radix.h:112
Facility for using an uint256 as a radix tree key.
TimePoint nextRequestTime
Definition: node.h:24
bool avaproofsSent
Definition: node.h:25
std::chrono::seconds nextPossibleConflictTime
Definition: peermanager.h:94
uint32_t node_count
Definition: peermanager.h:87
static constexpr auto DANGLING_TIMEOUT
Consider dropping the peer if no node is attached after this timeout expired.
Definition: peermanager.h:100
uint32_t index
Definition: peermanager.h:86
uint32_t getScore() const
Definition: peermanager.h:109
ProofRef proof
Definition: peermanager.h:89
uint64_t getStop() const
Definition: peermanager.h:73
uint64_t getStart() const
Definition: peermanager.h:72
PeerId getPeerId() const
Definition: peermanager.h:75
#define LOCK(cs)
Definition: sync.h:243
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:276
ArgsManager gArgs
Definition: system.cpp:77
static int count
Definition: tests.c:31
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1201
assert(!tx.IsCoinBase())