Bitcoin ABC  0.29.1
P2P Digital Currency
processor.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018-2019 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 #include <avalanche/processor.h>
6 
7 #include <avalanche/avalanche.h>
11 #include <avalanche/validation.h>
12 #include <avalanche/voterecord.h>
13 #include <chain.h>
14 #include <key_io.h> // For DecodeSecret
15 #include <net.h>
16 #include <netmessagemaker.h>
18 #include <scheduler.h>
19 #include <util/bitmanip.h>
20 #include <util/moneystr.h>
21 #include <util/time.h>
22 #include <util/translation.h>
23 #include <validation.h>
24 
25 #include <chrono>
26 #include <limits>
27 #include <tuple>
28 
32 static constexpr std::chrono::milliseconds AVALANCHE_TIME_STEP{10};
33 
34 static const std::string AVAPEERS_FILE_NAME{"avapeers.dat"};
35 
36 // Unfortunately, the bitcoind codebase is full of global and we are kinda
37 // forced into it here.
38 std::unique_ptr<avalanche::Processor> g_avalanche;
39 
40 namespace avalanche {
41 static const uint256 GetVoteItemId(const AnyVoteItem &item) {
42  return std::visit(variant::overloaded{
43  [](const ProofRef &proof) {
44  uint256 id = proof->getId();
45  return id;
46  },
47  [](const CBlockIndex *pindex) {
48  uint256 hash = pindex->GetBlockHash();
49  return hash;
50  },
51  [](const CTransactionRef &tx) {
52  uint256 id = tx->GetId();
53  return id;
54  },
55  },
56  item);
57 }
58 
59 static bool VerifyProof(const Amount &stakeUtxoDustThreshold,
60  const Proof &proof, bilingual_str &error) {
61  ProofValidationState proof_state;
62 
63  if (!proof.verify(stakeUtxoDustThreshold, proof_state)) {
64  switch (proof_state.GetResult()) {
66  error = _("The avalanche proof has no stake.");
67  return false;
69  error = _("The avalanche proof stake is too low.");
70  return false;
72  error = _("The avalanche proof has duplicated stake.");
73  return false;
75  error = _("The avalanche proof has invalid stake signatures.");
76  return false;
78  error = strprintf(
79  _("The avalanche proof has too many utxos (max: %u)."),
81  return false;
82  default:
83  error = _("The avalanche proof is invalid.");
84  return false;
85  }
86  }
87 
88  return true;
89 }
90 
91 static bool VerifyDelegation(const Delegation &dg,
92  const CPubKey &expectedPubKey,
94  DelegationState dg_state;
95 
96  CPubKey auth;
97  if (!dg.verify(dg_state, auth)) {
98  switch (dg_state.GetResult()) {
100  error = _("The avalanche delegation has invalid signatures.");
101  return false;
103  error = _(
104  "The avalanche delegation has too many delegation levels.");
105  return false;
106  default:
107  error = _("The avalanche delegation is invalid.");
108  return false;
109  }
110  }
111 
112  if (auth != expectedPubKey) {
113  error = _(
114  "The avalanche delegation does not match the expected public key.");
115  return false;
116  }
117 
118  return true;
119 }
120 
124 
127 };
128 
132 
133 public:
135 
137 
139  uint64_t mempool_sequence) override {
141  }
142 };
143 
145  CConnman *connmanIn, ChainstateManager &chainmanIn,
146  CTxMemPool *mempoolIn, CScheduler &scheduler,
147  std::unique_ptr<PeerData> peerDataIn, CKey sessionKeyIn,
148  uint32_t minQuorumTotalScoreIn,
149  double minQuorumConnectedScoreRatioIn,
150  int64_t minAvaproofsNodeCountIn,
151  uint32_t staleVoteThresholdIn, uint32_t staleVoteFactorIn,
152  Amount stakeUtxoDustThreshold, bool preConsensus)
153  : avaconfig(std::move(avaconfigIn)), connman(connmanIn),
154  chainman(chainmanIn), mempool(mempoolIn),
155  voteRecords(RWCollection<VoteMap>(VoteMap(VoteMapComparator(mempool)))),
156  round(0), peerManager(std::make_unique<PeerManager>(
157  stakeUtxoDustThreshold, chainman,
158  peerDataIn ? peerDataIn->proof : ProofRef())),
159  peerData(std::move(peerDataIn)), sessionKey(std::move(sessionKeyIn)),
160  minQuorumScore(minQuorumTotalScoreIn),
161  minQuorumConnectedScoreRatio(minQuorumConnectedScoreRatioIn),
162  minAvaproofsNodeCount(minAvaproofsNodeCountIn),
163  staleVoteThreshold(staleVoteThresholdIn),
164  staleVoteFactor(staleVoteFactorIn), m_preConsensus(preConsensus) {
165  // Make sure we get notified of chain state changes.
167  chain.handleNotifications(std::make_shared<NotificationsHandler>(this));
168 
169  scheduler.scheduleEvery(
170  [this]() -> bool {
171  std::unordered_set<ProofRef, SaltedProofHasher> registeredProofs;
173  peerManager->cleanupDanglingProofs(registeredProofs));
174  for (const auto &proof : registeredProofs) {
176  "Promoting previously dangling proof %s\n",
177  proof->getId().ToString());
178  reconcileOrFinalize(proof);
179  }
180  return true;
181  },
182  5min);
183 
184  if (!gArgs.GetBoolArg("-persistavapeers", DEFAULT_PERSIST_AVAPEERS)) {
185  return;
186  }
187 
188  std::unordered_set<ProofRef, SaltedProofHasher> registeredProofs;
189 
190  // Attempt to load the peer file if it exists.
191  const fs::path dumpPath = gArgs.GetDataDirNet() / AVAPEERS_FILE_NAME;
192  WITH_LOCK(cs_peerManager, return peerManager->loadPeersFromFile(
193  dumpPath, registeredProofs));
194 
195  // We just loaded the previous finalization status, but make sure to trigger
196  // another round of vote for these proofs to avoid issue if the network
197  // status changed since the peers file was dumped.
198  for (const auto &proof : registeredProofs) {
199  addToReconcile(proof);
200  }
201 
202  LogPrint(BCLog::AVALANCHE, "Loaded %d peers from the %s file\n",
203  registeredProofs.size(), PathToString(dumpPath));
204 }
205 
208  stopEventLoop();
209 
210  if (!gArgs.GetBoolArg("-persistavapeers", DEFAULT_PERSIST_AVAPEERS)) {
211  return;
212  }
213 
215  // Discard the status output: if it fails we want to continue normally.
216  peerManager->dumpPeersToFile(gArgs.GetDataDirNet() / AVAPEERS_FILE_NAME);
217 }
218 
219 std::unique_ptr<Processor>
221  CConnman *connman, ChainstateManager &chainman,
222  CTxMemPool *mempool, CScheduler &scheduler,
223  bilingual_str &error) {
224  std::unique_ptr<PeerData> peerData;
225  CKey masterKey;
227 
228  Amount stakeUtxoDustThreshold = PROOF_DUST_THRESHOLD;
229  if (argsman.IsArgSet("-avaproofstakeutxodustthreshold") &&
230  !ParseMoney(argsman.GetArg("-avaproofstakeutxodustthreshold", ""),
231  stakeUtxoDustThreshold)) {
232  error = _("The avalanche stake utxo dust threshold amount is invalid.");
233  return nullptr;
234  }
235 
236  if (argsman.IsArgSet("-avasessionkey")) {
237  sessionKey = DecodeSecret(argsman.GetArg("-avasessionkey", ""));
238  if (!sessionKey.IsValid()) {
239  error = _("The avalanche session key is invalid.");
240  return nullptr;
241  }
242  } else {
243  // Pick a random key for the session.
244  sessionKey.MakeNewKey(true);
245  }
246 
247  if (argsman.IsArgSet("-avaproof")) {
248  if (!argsman.IsArgSet("-avamasterkey")) {
249  error = _(
250  "The avalanche master key is missing for the avalanche proof.");
251  return nullptr;
252  }
253 
254  masterKey = DecodeSecret(argsman.GetArg("-avamasterkey", ""));
255  if (!masterKey.IsValid()) {
256  error = _("The avalanche master key is invalid.");
257  return nullptr;
258  }
259 
260  auto proof = RCUPtr<Proof>::make();
261  if (!Proof::FromHex(*proof, argsman.GetArg("-avaproof", ""), error)) {
262  // error is set by FromHex
263  return nullptr;
264  }
265 
266  peerData = std::make_unique<PeerData>();
267  peerData->proof = std::move(proof);
268  if (!VerifyProof(stakeUtxoDustThreshold, *peerData->proof, error)) {
269  // error is set by VerifyProof
270  return nullptr;
271  }
272 
273  std::unique_ptr<DelegationBuilder> dgb;
274  const CPubKey &masterPubKey = masterKey.GetPubKey();
275 
276  if (argsman.IsArgSet("-avadelegation")) {
277  Delegation dg;
278  if (!Delegation::FromHex(dg, argsman.GetArg("-avadelegation", ""),
279  error)) {
280  // error is set by FromHex()
281  return nullptr;
282  }
283 
284  if (dg.getProofId() != peerData->proof->getId()) {
285  error = _("The delegation does not match the proof.");
286  return nullptr;
287  }
288 
289  if (masterPubKey != dg.getDelegatedPubkey()) {
290  error = _(
291  "The master key does not match the delegation public key.");
292  return nullptr;
293  }
294 
295  dgb = std::make_unique<DelegationBuilder>(dg);
296  } else {
297  if (masterPubKey != peerData->proof->getMaster()) {
298  error =
299  _("The master key does not match the proof public key.");
300  return nullptr;
301  }
302 
303  dgb = std::make_unique<DelegationBuilder>(*peerData->proof);
304  }
305 
306  // Generate the delegation to the session key.
307  const CPubKey sessionPubKey = sessionKey.GetPubKey();
308  if (sessionPubKey != masterPubKey) {
309  if (!dgb->addLevel(masterKey, sessionPubKey)) {
310  error = _("Failed to generate a delegation for this session.");
311  return nullptr;
312  }
313  }
314  peerData->delegation = dgb->build();
315 
316  if (!VerifyDelegation(peerData->delegation, sessionPubKey, error)) {
317  // error is set by VerifyDelegation
318  return nullptr;
319  }
320  }
321 
322  const auto queryTimeoutDuration =
323  std::chrono::milliseconds(argsman.GetIntArg(
324  "-avatimeout", AVALANCHE_DEFAULT_QUERY_TIMEOUT.count()));
325 
326  // Determine quorum parameters
328  if (argsman.IsArgSet("-avaminquorumstake") &&
329  !ParseMoney(argsman.GetArg("-avaminquorumstake", ""), minQuorumStake)) {
330  error = _("The avalanche min quorum stake amount is invalid.");
331  return nullptr;
332  }
333 
334  if (!MoneyRange(minQuorumStake)) {
335  error = _("The avalanche min quorum stake amount is out of range.");
336  return nullptr;
337  }
338 
339  double minQuorumConnectedStakeRatio =
341  if (argsman.IsArgSet("-avaminquorumconnectedstakeratio") &&
342  !ParseDouble(argsman.GetArg("-avaminquorumconnectedstakeratio", ""),
343  &minQuorumConnectedStakeRatio)) {
344  error = _("The avalanche min quorum connected stake ratio is invalid.");
345  return nullptr;
346  }
347 
348  if (minQuorumConnectedStakeRatio < 0 || minQuorumConnectedStakeRatio > 1) {
349  error = _(
350  "The avalanche min quorum connected stake ratio is out of range.");
351  return nullptr;
352  }
353 
354  int64_t minAvaproofsNodeCount =
355  argsman.GetIntArg("-avaminavaproofsnodecount",
357  if (minAvaproofsNodeCount < 0) {
358  error = _("The minimum number of node that sent avaproofs message "
359  "should be non-negative");
360  return nullptr;
361  }
362 
363  // Determine voting parameters
364  int64_t staleVoteThreshold = argsman.GetIntArg(
365  "-avastalevotethreshold", AVALANCHE_VOTE_STALE_THRESHOLD);
367  error = strprintf(_("The avalanche stale vote threshold must be "
368  "greater than or equal to %d"),
370  return nullptr;
371  }
372  if (staleVoteThreshold > std::numeric_limits<uint32_t>::max()) {
373  error = strprintf(_("The avalanche stale vote threshold must be less "
374  "than or equal to %d"),
375  std::numeric_limits<uint32_t>::max());
376  return nullptr;
377  }
378 
379  int64_t staleVoteFactor =
380  argsman.GetIntArg("-avastalevotefactor", AVALANCHE_VOTE_STALE_FACTOR);
381  if (staleVoteFactor <= 0) {
382  error = _("The avalanche stale vote factor must be greater than 0");
383  return nullptr;
384  }
385  if (staleVoteFactor > std::numeric_limits<uint32_t>::max()) {
386  error = strprintf(_("The avalanche stale vote factor must be less than "
387  "or equal to %d"),
388  std::numeric_limits<uint32_t>::max());
389  return nullptr;
390  }
391 
392  Config avaconfig(queryTimeoutDuration);
393 
394  // We can't use std::make_unique with a private constructor
395  return std::unique_ptr<Processor>(new Processor(
396  std::move(avaconfig), chain, connman, chainman, mempool, scheduler,
397  std::move(peerData), std::move(sessionKey),
398  Proof::amountToScore(minQuorumStake), minQuorumConnectedStakeRatio,
400  stakeUtxoDustThreshold,
401  argsman.GetBoolArg("-avalanchepreconsensus",
403 }
404 
405 static bool isNull(const AnyVoteItem &item) {
406  return item.valueless_by_exception() ||
407  std::visit([](const auto &item) { return item == nullptr; }, item);
408 };
409 
411  if (isNull(item)) {
412  return false;
413  }
414 
415  if (!isWorthPolling(item)) {
416  return false;
417  }
418 
419  // getLocalAcceptance() takes the voteRecords read lock, so we can't inline
420  // the calls or we get a deadlock.
421  const bool accepted = getLocalAcceptance(item);
422 
423  return voteRecords.getWriteView()
424  ->insert(std::make_pair(item, VoteRecord(accepted)))
425  .second;
426 }
427 
429  if (!proof) {
430  return false;
431  }
432 
433  if (isRecentlyFinalized(proof->getId())) {
434  PeerId peerid;
436  if (peerManager->forPeer(proof->getId(), [&](const Peer &peer) {
437  peerid = peer.peerid;
438  return true;
439  })) {
440  return peerManager->setFinalized(peerid);
441  }
442  }
443 
444  return addToReconcile(proof);
445 }
446 
447 bool Processor::isAccepted(const AnyVoteItem &item) const {
448  if (isNull(item)) {
449  return false;
450  }
451 
452  auto r = voteRecords.getReadView();
453  auto it = r->find(item);
454  if (it == r.end()) {
455  return false;
456  }
457 
458  return it->second.isAccepted();
459 }
460 
461 int Processor::getConfidence(const AnyVoteItem &item) const {
462  if (isNull(item)) {
463  return -1;
464  }
465 
466  auto r = voteRecords.getReadView();
467  auto it = r->find(item);
468  if (it == r.end()) {
469  return -1;
470  }
471 
472  return it->second.getConfidence();
473 }
474 
475 bool Processor::isRecentlyFinalized(const uint256 &itemId) const {
476  return WITH_LOCK(cs_finalizedItems, return finalizedItems.contains(itemId));
477 }
478 
481  finalizedItems.reset();
482 }
483 
484 namespace {
489  class TCPResponse {
490  Response response;
492 
493  public:
494  TCPResponse(Response responseIn, const CKey &key)
495  : response(std::move(responseIn)) {
496  CHashWriter hasher(SER_GETHASH, 0);
497  hasher << response;
498  const uint256 hash = hasher.GetHash();
499 
500  // Now let's sign!
501  if (!key.SignSchnorr(hash, sig)) {
502  sig.fill(0);
503  }
504  }
505 
506  // serialization support
507  SERIALIZE_METHODS(TCPResponse, obj) {
508  READWRITE(obj.response, obj.sig);
509  }
510  };
511 } // namespace
512 
515  pfrom, CNetMsgMaker(pfrom->GetCommonVersion())
517  TCPResponse(std::move(response), sessionKey)));
518 }
519 
521  std::vector<VoteItemUpdate> &updates,
522  int &banscore, std::string &error) {
523  {
524  // Save the time at which we can query again.
526 
527  // FIXME: This will override the time even when we received an old stale
528  // message. This should check that the message is indeed the most up to
529  // date one before updating the time.
530  peerManager->updateNextRequestTime(
531  nodeid, Now<SteadyMilliseconds>() +
532  std::chrono::milliseconds(response.getCooldown()));
533  }
534 
535  std::vector<CInv> invs;
536 
537  {
538  // Check that the query exists. There is a possibility that it has been
539  // deleted if the query timed out, so we don't increase the ban score to
540  // slowly banning nodes for poor networking over time. Banning has to be
541  // handled at callsite to avoid DoS.
542  auto w = queries.getWriteView();
543  auto it = w->find(std::make_tuple(nodeid, response.getRound()));
544  if (it == w.end()) {
545  banscore = 0;
546  error = "unexpected-ava-response";
547  return false;
548  }
549 
550  invs = std::move(it->invs);
551  w->erase(it);
552  }
553 
554  // Verify that the request and the vote are consistent.
555  const std::vector<Vote> &votes = response.GetVotes();
556  size_t size = invs.size();
557  if (votes.size() != size) {
558  banscore = 100;
559  error = "invalid-ava-response-size";
560  return false;
561  }
562 
563  for (size_t i = 0; i < size; i++) {
564  if (invs[i].hash != votes[i].GetHash()) {
565  banscore = 100;
566  error = "invalid-ava-response-content";
567  return false;
568  }
569  }
570 
571  std::map<AnyVoteItem, Vote, VoteMapComparator> responseItems(
573 
574  // At this stage we are certain that invs[i] matches votes[i], so we can use
575  // the inv type to retrieve what is being voted on.
576  for (size_t i = 0; i < size; i++) {
577  auto item = getVoteItemFromInv(invs[i]);
578 
579  if (isNull(item)) {
580  // This should not happen, but just in case...
581  continue;
582  }
583 
584  if (!isWorthPolling(item)) {
585  // There is no point polling this item.
586  continue;
587  }
588 
589  responseItems.insert(std::make_pair(std::move(item), votes[i]));
590  }
591 
592  auto voteRecordsWriteView = voteRecords.getWriteView();
593 
594  // Register votes.
595  for (const auto &p : responseItems) {
596  auto item = p.first;
597  const Vote &v = p.second;
598 
599  auto it = voteRecordsWriteView->find(item);
600  if (it == voteRecordsWriteView.end()) {
601  // We are not voting on that item anymore.
602  continue;
603  }
604 
605  auto &vr = it->second;
606  if (!vr.registerVote(nodeid, v.GetError())) {
607  if (vr.isStale(staleVoteThreshold, staleVoteFactor)) {
608  updates.emplace_back(std::move(item), VoteStatus::Stale);
609 
610  // Just drop stale votes. If we see this item again, we'll
611  // do a new vote.
612  voteRecordsWriteView->erase(it);
613  }
614  // This vote did not provide any extra information, move on.
615  continue;
616  }
617 
618  if (!vr.hasFinalized()) {
619  // This item has not been finalized, so we have nothing more to
620  // do.
621  updates.emplace_back(std::move(item), vr.isAccepted()
624  continue;
625  }
626 
627  // We just finalized a vote. If it is valid, then let the caller
628  // know. Either way, remove the item from the map.
629  updates.emplace_back(std::move(item), vr.isAccepted()
632  voteRecordsWriteView->erase(it);
633  }
634 
635  // FIXME This doesn't belong here as it has nothing to do with vote
636  // registration.
637  for (const auto &update : updates) {
638  if (update.getStatus() != VoteStatus::Finalized &&
639  update.getStatus() != VoteStatus::Invalid) {
640  continue;
641  }
642 
643  const auto &item = update.getVoteItem();
644 
645  if (update.getStatus() == VoteStatus::Finalized) {
646  // Always track finalized items regardless of type. Once finalized
647  // they should never become invalid.
649  return finalizedItems.insert(GetVoteItemId(item)));
650  }
651 
652  if (!std::holds_alternative<const CBlockIndex *>(item)) {
653  continue;
654  }
655 
656  if (update.getStatus() == VoteStatus::Invalid) {
657  // Track invalidated blocks. Other invalidated types are not
658  // tracked because they may be rejected for transient reasons
659  // (ex: immature proofs or orphaned txs) With blocks this is not
660  // the case. A rejected block will not be mined on. To prevent
661  // reorgs, invalidated blocks should never be polled again.
663  invalidatedBlocks.insert(GetVoteItemId(item));
664  continue;
665  }
666 
667  // At this point the block index can only be finalized
668  const CBlockIndex *pindex = std::get<const CBlockIndex *>(item);
670  if (finalizationTip &&
671  finalizationTip->GetAncestor(pindex->nHeight) == pindex) {
672  continue;
673  }
674 
675  finalizationTip = pindex;
676  }
677 
678  return true;
679 }
680 
682  return sessionKey.GetPubKey();
683 }
684 
687 
688  Delegation delegation;
689  if (peerData) {
690  if (!canShareLocalProof()) {
691  if (!delayedAvahelloNodeIds.emplace(pfrom->GetId()).second) {
692  // Nothing to do
693  return false;
694  }
695  } else {
696  delegation = peerData->delegation;
697  }
698  }
699 
700  CHashWriter hasher(SER_GETHASH, 0);
701  hasher << delegation.getId();
702  hasher << pfrom->GetLocalNonce();
703  hasher << pfrom->nRemoteHostNonce;
704  hasher << pfrom->GetLocalExtraEntropy();
705  hasher << pfrom->nRemoteExtraEntropy;
706 
707  // Now let's sign!
708  SchnorrSig sig;
709  if (!sessionKey.SignSchnorr(hasher.GetHash(), sig)) {
710  return false;
711  }
712 
714  pfrom, CNetMsgMaker(pfrom->GetCommonVersion())
715  .Make(NetMsgType::AVAHELLO, Hello(delegation, sig)));
716 
717  return delegation.getLimitedProofId() != uint256::ZERO;
718 }
719 
722  return sendHelloInternal(pfrom));
723 }
724 
727 
728  auto it = delayedAvahelloNodeIds.begin();
729  while (it != delayedAvahelloNodeIds.end()) {
730  if (connman->ForNode(*it, [&](CNode *pnode) EXCLUSIVE_LOCKS_REQUIRED(
732  return sendHelloInternal(pnode);
733  })) {
734  // Our proof has been announced to this node
735  it = delayedAvahelloNodeIds.erase(it);
736  } else {
737  ++it;
738  }
739  }
740 }
741 
743  return peerData ? peerData->proof : ProofRef();
744 }
745 
747  return peerData
748  ? WITH_LOCK(peerData->cs_proofState, return peerData->proofState)
750 }
751 
753  return eventLoop.startEventLoop(
754  scheduler, [this]() { this->runEventLoop(); }, AVALANCHE_TIME_STEP);
755 }
756 
758  return eventLoop.stopEventLoop();
759 }
760 
763 
764  if (chainman.ActiveChainstate().IsInitialBlockDownload()) {
765  // Before IBD is complete there is no way to make sure a proof is valid
766  // or not, e.g. it can be spent in a block we don't know yet. In order
767  // to increase confidence that our proof set is similar to other nodes
768  // on the network, the messages received during IBD are not accounted.
769  return;
770  }
771 
773  if (peerManager->latchAvaproofsSent(nodeid)) {
775  }
776 }
777 
778 /*
779  * Returns a bool indicating whether we have a usable Avalanche quorum enabling
780  * us to take decisions based on polls.
781  */
784 
785  {
787  if (peerManager->getNodeCount() < 8) {
788  // There is no point polling if we know the vote cannot converge
789  return false;
790  }
791  }
792 
793  /*
794  * The following parameters can naturally go temporarly below the threshold
795  * under normal circumstances, like during a proof replacement with a lower
796  * stake amount, or the discovery of a new proofs for which we don't have a
797  * node yet.
798  * In order to prevent our node from starting and stopping the polls
799  * spuriously on such event, the quorum establishement is latched. The only
800  * parameters that should not latched is the minimum node count, as this
801  * would cause the poll to be inconclusive anyway and should not happen
802  * under normal circumstances.
803  */
804  if (quorumIsEstablished) {
805  return true;
806  }
807 
808  // Don't do Avalanche while node is IBD'ing
809  if (chainman.ActiveChainstate().IsInitialBlockDownload()) {
810  return false;
811  }
812 
814  return false;
815  }
816 
817  auto localProof = getLocalProof();
818 
819  // Get the registered proof score and registered score we have nodes for
820  uint32_t totalPeersScore;
821  uint32_t connectedPeersScore;
822  {
824  totalPeersScore = peerManager->getTotalPeersScore();
825  connectedPeersScore = peerManager->getConnectedPeersScore();
826 
827  // Consider that we are always connected to our proof, even if we are
828  // the single node using that proof.
829  if (localProof &&
830  peerManager->forPeer(localProof->getId(), [](const Peer &peer) {
831  return peer.node_count == 0;
832  })) {
833  connectedPeersScore += localProof->getScore();
834  }
835  }
836 
837  // Ensure enough is being staked overall
838  if (totalPeersScore < minQuorumScore) {
839  return false;
840  }
841 
842  // Ensure we have connected score for enough of the overall score
843  uint32_t minConnectedScore =
844  std::round(double(totalPeersScore) * minQuorumConnectedScoreRatio);
845  if (connectedPeersScore < minConnectedScore) {
846  return false;
847  }
848 
849  quorumIsEstablished = true;
850 
851  // Attempt to compute the staking rewards winner now so we don't have to
852  // wait for a block if we already have all the prerequisites.
853  const CBlockIndex *pprev = WITH_LOCK(cs_main, return chainman.ActiveTip());
854  if (pprev && IsStakingRewardsActivated(
855  GetConfig().GetChainParams().GetConsensus(), pprev)) {
856  computeStakingReward(pprev);
857  }
858 
859  return true;
860 }
861 
863  // The flag is latched
864  if (m_canShareLocalProof) {
865  return true;
866  }
867 
868  // Don't share our proof if we don't have any inbound connection.
869  // This is a best effort measure to prevent advertising a proof if we have
870  // limited network connectivity.
872 
873  return m_canShareLocalProof;
874 }
875 
877  if (!pindex) {
878  return false;
879  }
880 
881  // If the quorum is not established there is no point picking a winner that
882  // will be rejected.
883  if (!isQuorumEstablished()) {
884  return false;
885  }
886 
887  {
889  if (stakingRewards.count(pindex->GetBlockHash()) > 0) {
890  return true;
891  }
892  }
893 
894  StakingReward _stakingRewards;
895  _stakingRewards.blockheight = pindex->nHeight;
896 
897  if (WITH_LOCK(cs_peerManager, return peerManager->selectStakingRewardWinner(
898  pindex, _stakingRewards.winners))) {
900  return stakingRewards
901  .emplace(pindex->GetBlockHash(), std::move(_stakingRewards))
902  .second;
903  }
904 
905  return false;
906 }
907 
908 bool Processor::eraseStakingRewardWinner(const BlockHash &prevBlockHash) {
910  return stakingRewards.erase(prevBlockHash) > 0;
911 }
912 
913 void Processor::cleanupStakingRewards(const int minHeight) {
915  // std::erase_if is only defined since C++20
916  for (auto it = stakingRewards.begin(); it != stakingRewards.end();) {
917  if (it->second.blockheight < minHeight) {
918  it = stakingRewards.erase(it);
919  } else {
920  ++it;
921  }
922  }
923 }
924 
926  std::vector<CScript> &winners) const {
928  auto it = stakingRewards.find(prevBlockHash);
929  if (it == stakingRewards.end()) {
930  return false;
931  }
932 
933  winners = it->second.winners;
934  return true;
935 }
936 
938  const std::vector<CScript> &winners) {
939  assert(pprev);
940 
941  StakingReward stakingReward;
942  stakingReward.blockheight = pprev->nHeight;
943  stakingReward.winners = winners;
944 
946  return stakingRewards.insert_or_assign(pprev->GetBlockHash(), stakingReward)
947  .second;
948 }
949 
950 void Processor::FinalizeNode(const ::Config &config, const CNode &node) {
952 
953  const NodeId nodeid = node.GetId();
954  WITH_LOCK(cs_peerManager, peerManager->removeNode(nodeid));
955  WITH_LOCK(cs_delayedAvahelloNodeIds, delayedAvahelloNodeIds.erase(nodeid));
956 }
957 
959  const bool registerLocalProof = canShareLocalProof();
960  auto registerProofs = [&]() {
962 
963  auto registeredProofs = peerManager->updatedBlockTip();
964 
965  ProofRegistrationState localProofState;
966  if (peerData && peerData->proof && registerLocalProof) {
967  if (peerManager->registerProof(peerData->proof, localProofState)) {
968  registeredProofs.insert(peerData->proof);
969  }
970 
971  if (localProofState.GetResult() ==
973  // If our proof already exists, that's fine but we don't want to
974  // erase the state with a duplicated proof status, so let's
975  // retrieve the proper state. It also means we are able to
976  // update the status should the proof move from one pool to the
977  // other.
978  const ProofId &localProofId = peerData->proof->getId();
979  if (peerManager->isImmature(localProofId)) {
981  "immature-proof");
982  }
983  if (peerManager->isInConflictingPool(localProofId)) {
984  localProofState.Invalid(
986  "conflicting-utxos");
987  }
988  if (peerManager->isBoundToPeer(localProofId)) {
989  localProofState = ProofRegistrationState();
990  }
991  }
992 
993  WITH_LOCK(peerData->cs_proofState,
994  peerData->proofState = std::move(localProofState));
995  }
996 
997  return registeredProofs;
998  };
999 
1000  auto registeredProofs = registerProofs();
1001  for (const auto &proof : registeredProofs) {
1002  reconcileOrFinalize(proof);
1003  }
1004 }
1005 
1007  if (m_preConsensus) {
1008  addToReconcile(tx);
1009  }
1010 }
1011 
1013  // Don't poll if quorum hasn't been established yet
1014  if (!isQuorumEstablished()) {
1015  return;
1016  }
1017 
1018  // First things first, check if we have requests that timed out and clear
1019  // them.
1021 
1022  // Make sure there is at least one suitable node to query before gathering
1023  // invs.
1024  NodeId nodeid = WITH_LOCK(cs_peerManager, return peerManager->selectNode());
1025  if (nodeid == NO_NODE) {
1026  return;
1027  }
1028  std::vector<CInv> invs = getInvsForNextPoll();
1029  if (invs.empty()) {
1030  return;
1031  }
1032 
1034 
1035  do {
1041  bool hasSent = connman->ForNode(
1042  nodeid, [this, &invs](CNode *pnode) EXCLUSIVE_LOCKS_REQUIRED(
1043  cs_peerManager) {
1044  uint64_t current_round = round++;
1045 
1046  {
1047  // Compute the time at which this requests times out.
1048  auto timeout = Now<SteadyMilliseconds>() +
1050  // Register the query.
1051  queries.getWriteView()->insert(
1052  {pnode->GetId(), current_round, timeout, invs});
1053  // Set the timeout.
1054  peerManager->updateNextRequestTime(pnode->GetId(), timeout);
1055  }
1056 
1057  pnode->invsPolled(invs.size());
1058 
1059  // Send the query to the node.
1061  pnode, CNetMsgMaker(pnode->GetCommonVersion())
1063  Poll(current_round, std::move(invs))));
1064  return true;
1065  });
1066 
1067  // Success!
1068  if (hasSent) {
1069  return;
1070  }
1071 
1072  // This node is obsolete, delete it.
1073  peerManager->removeNode(nodeid);
1074 
1075  // Get next suitable node to try again
1076  nodeid = peerManager->selectNode();
1077  } while (nodeid != NO_NODE);
1078 }
1079 
1081  auto now = Now<SteadyMilliseconds>();
1082  std::map<CInv, uint8_t> timedout_items{};
1083 
1084  {
1085  // Clear expired requests.
1086  auto w = queries.getWriteView();
1087  auto it = w->get<query_timeout>().begin();
1088  while (it != w->get<query_timeout>().end() && it->timeout < now) {
1089  for (const auto &i : it->invs) {
1090  timedout_items[i]++;
1091  }
1092 
1093  w->get<query_timeout>().erase(it++);
1094  }
1095  }
1096 
1097  if (timedout_items.empty()) {
1098  return;
1099  }
1100 
1101  // In flight request accounting.
1102  auto voteRecordsWriteView = voteRecords.getWriteView();
1103  for (const auto &p : timedout_items) {
1104  auto item = getVoteItemFromInv(p.first);
1105 
1106  if (isNull(item)) {
1107  continue;
1108  }
1109 
1110  auto it = voteRecordsWriteView->find(item);
1111  if (it == voteRecordsWriteView.end()) {
1112  continue;
1113  }
1114 
1115  it->second.clearInflightRequest(p.second);
1116  }
1117 }
1118 
1119 std::vector<CInv> Processor::getInvsForNextPoll(bool forPoll) {
1120  std::vector<CInv> invs;
1121 
1122  {
1123  // First remove all items that are not worth polling.
1124  auto w = voteRecords.getWriteView();
1125  for (auto it = w->begin(); it != w->end();) {
1126  if (!isWorthPolling(it->first)) {
1127  it = w->erase(it);
1128  } else {
1129  ++it;
1130  }
1131  }
1132  }
1133 
1134  auto buildInvFromVoteItem = variant::overloaded{
1135  [](const ProofRef &proof) {
1136  return CInv(MSG_AVA_PROOF, proof->getId());
1137  },
1138  [](const CBlockIndex *pindex) {
1139  return CInv(MSG_BLOCK, pindex->GetBlockHash());
1140  },
1141  [](const CTransactionRef &tx) { return CInv(MSG_TX, tx->GetHash()); },
1142  };
1143 
1144  auto r = voteRecords.getReadView();
1145  for (const auto &[item, voteRecord] : r) {
1146  if (invs.size() >= AVALANCHE_MAX_ELEMENT_POLL) {
1147  // Make sure we do not produce more invs than specified by the
1148  // protocol.
1149  return invs;
1150  }
1151 
1152  const bool shouldPoll =
1153  forPoll ? voteRecord.registerPoll() : voteRecord.shouldPoll();
1154 
1155  if (!shouldPoll) {
1156  continue;
1157  }
1158 
1159  invs.emplace_back(std::visit(buildInvFromVoteItem, item));
1160  }
1161 
1162  return invs;
1163 }
1164 
1166  if (inv.IsMsgBlk()) {
1168  BlockHash(inv.hash)));
1169  }
1170 
1171  if (inv.IsMsgProof()) {
1172  return WITH_LOCK(cs_peerManager,
1173  return peerManager->getProof(ProofId(inv.hash)));
1174  }
1175 
1176  if (mempool && inv.IsMsgTx()) {
1177  return WITH_LOCK(mempool->cs, return mempool->get(TxId(inv.hash)));
1178  }
1179 
1180  return {nullptr};
1181 }
1182 
1185 
1186  LOCK(cs_main);
1187 
1188  if (pindex->nStatus.isInvalid()) {
1189  // No point polling invalid blocks.
1190  return false;
1191  }
1192 
1194  return processor.finalizationTip &&
1195  processor.finalizationTip->GetAncestor(
1196  pindex->nHeight) == pindex)) {
1197  // There is no point polling blocks that are ancestor of a block that
1198  // has been accepted by the network.
1199  return false;
1200  }
1201 
1203  return processor.invalidatedBlocks.contains(
1204  pindex->GetBlockHash()))) {
1205  // Blocks invalidated by Avalanche should not be polled twice.
1206  return false;
1207  }
1208 
1209  return true;
1210 }
1211 
1213  // Avoid lock order issues cs_main -> cs_peerManager
1215  AssertLockNotHeld(processor.cs_peerManager);
1216 
1217  const ProofId &proofid = proof->getId();
1218 
1219  LOCK(processor.cs_peerManager);
1220 
1221  // No point polling immature or discarded proofs
1222  return processor.peerManager->isBoundToPeer(proofid) ||
1223  processor.peerManager->isInConflictingPool(proofid);
1224 }
1225 
1227  if (!processor.mempool) {
1228  return false;
1229  }
1230 
1231  // TODO For now the transactions with conflicts or rejected by policies are
1232  // not stored anywhere, so only the mempool transactions are worth polling.
1233  AssertLockNotHeld(processor.mempool->cs);
1234  return WITH_LOCK(processor.mempool->cs,
1235  return processor.mempool->exists(tx->GetId()));
1236 }
1237 
1238 bool Processor::isWorthPolling(const AnyVoteItem &item) const {
1239  return std::visit(IsWorthPolling(*this), item) &&
1241 }
1242 
1244  const CBlockIndex *pindex) const {
1246 
1247  return WITH_LOCK(cs_main,
1248  return processor.chainman.ActiveChain().Contains(pindex));
1249 }
1250 
1252  AssertLockNotHeld(processor.cs_peerManager);
1253 
1254  return WITH_LOCK(
1255  processor.cs_peerManager,
1256  return processor.peerManager->isBoundToPeer(proof->getId()));
1257 }
1258 
1260  const CTransactionRef &tx) const {
1261  if (!processor.mempool) {
1262  return false;
1263  }
1264 
1265  AssertLockNotHeld(processor.mempool->cs);
1266 
1267  return WITH_LOCK(processor.mempool->cs,
1268  return processor.mempool->exists(tx->GetId()));
1269 }
1270 
1271 } // namespace avalanche
bool MoneyRange(const Amount nValue)
Definition: amount.h:166
uint32_t PeerId
Definition: node.h:15
static constexpr bool DEFAULT_PERSIST_AVAPEERS
Default for -persistavapeers.
Definition: avalanche.h:63
static constexpr double AVALANCHE_DEFAULT_MIN_QUORUM_CONNECTED_STAKE_RATIO
Default minimum percentage of stake-weighted peers we must have a node for to constitute a usable quo...
Definition: avalanche.h:53
static constexpr double AVALANCHE_DEFAULT_MIN_AVAPROOFS_NODE_COUNT
Default minimum number of nodes that sent us an avaproofs message before we can consider our quorum s...
Definition: avalanche.h:60
static constexpr bool DEFAULT_AVALANCHE_PRECONSENSUS
Default for -avalanchepreconsensus.
Definition: avalanche.h:66
static constexpr Amount AVALANCHE_DEFAULT_MIN_QUORUM_STAKE
Default minimum cumulative stake of all known peers that constitutes a usable quorum.
Definition: avalanche.h:46
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: system.cpp:490
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: system.h:266
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: system.cpp:635
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:603
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:665
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:26
BlockHash GetBlockHash() const
Definition: blockindex.h:147
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:39
Definition: net.h:845
size_t GetNodeCount(NumConnections num) const
Definition: net.cpp:3249
bool ForNode(NodeId id, std::function< bool(CNode *pnode)> func)
Definition: net.cpp:3539
@ CONNECTIONS_IN
Definition: net.h:849
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
Definition: net.cpp:3494
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:99
uint256 GetHash()
Compute the double-SHA256 hash of all data written to this object.
Definition: hash.h:122
Inv(ventory) message data.
Definition: protocol.h:580
bool IsMsgBlk() const
Definition: protocol.h:607
bool IsMsgTx() const
Definition: protocol.h:599
uint256 hash
Definition: protocol.h:583
bool IsMsgProof() const
Definition: protocol.h:603
An encapsulated secp256k1 private key.
Definition: key.h:28
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:94
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:183
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:210
bool SignSchnorr(const uint256 &hash, SchnorrSig &sig, uint32_t test_case=0) const
Create a Schnorr signature.
Definition: key.cpp:288
CSerializedNetMsg Make(int nFlags, std::string msg_type, Args &&...args) const
Information about a peer.
Definition: net.h:456
NodeId GetId() const
Definition: net.h:712
uint64_t GetLocalNonce() const
Definition: net.h:714
int GetCommonVersion() const
Definition: net.h:738
uint64_t nRemoteHostNonce
Definition: net.h:497
uint64_t nRemoteExtraEntropy
Definition: net.h:499
uint64_t GetLocalExtraEntropy() const
Definition: net.h:715
void invsPolled(uint32_t count)
The node was polled for count invs.
Definition: net.cpp:3418
An encapsulated public key.
Definition: pubkey.h:31
Simple class for background tasks that should be run periodically or once "after a while".
Definition: scheduler.h:41
void scheduleEvery(Predicate p, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Repeat p until it return false.
Definition: scheduler.cpp:114
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:209
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:296
CTransactionRef get(const TxId &txid) const
Definition: txmempool.cpp:490
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1142
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1354
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1270
static RCUPtr make(Args &&...args)
Construct a new object that is owned by the pointer.
Definition: rcu.h:112
ReadView getReadView() const
Definition: rwcollection.h:78
WriteView getWriteView()
Definition: rwcollection.h:84
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
Definition: validation.h:94
Result GetResult() const
Definition: validation.h:115
ProofId getProofId() const
Definition: delegation.cpp:56
static bool FromHex(Delegation &dg, const std::string &dgHex, bilingual_str &errorOut)
Definition: delegation.cpp:16
bool verify(DelegationState &state, CPubKey &auth) const
Definition: delegation.cpp:73
const LimitedProofId & getLimitedProofId() const
Definition: delegation.h:61
const CPubKey & getDelegatedPubkey() const
Definition: delegation.cpp:60
const DelegationId & getId() const
Definition: delegation.h:60
void transactionAddedToMempool(const CTransactionRef &tx, uint64_t mempool_sequence) override
Definition: processor.cpp:138
void sendResponse(CNode *pfrom, Response response) const
Definition: processor.cpp:513
const uint32_t staleVoteThreshold
Voting parameters.
Definition: processor.h:253
std::atomic< bool > quorumIsEstablished
Definition: processor.h:247
AnyVoteItem getVoteItemFromInv(const CInv &inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
Definition: processor.cpp:1165
Mutex cs_finalizedItems
Rolling bloom filter to track recently finalized inventory items of any type.
Definition: processor.h:417
bool sendHelloInternal(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(cs_delayedAvahelloNodeIds)
Definition: processor.cpp:685
int getConfidence(const AnyVoteItem &item) const
Definition: processor.cpp:461
bool addToReconcile(const AnyVoteItem &item) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:410
std::vector< CInv > getInvsForNextPoll(bool forPoll=true) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:1119
RWCollection< QuerySet > queries
Definition: processor.h:232
bool getStakingRewardWinners(const BlockHash &prevBlockHash, std::vector< CScript > &winners) const EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards)
Definition: processor.cpp:925
bool registerVotes(NodeId nodeid, const Response &response, std::vector< VoteItemUpdate > &updates, int &banscore, std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:520
void transactionAddedToMempool(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:1006
bool sendHello(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Send a avahello message.
Definition: processor.cpp:720
bool isRecentlyFinalized(const uint256 &itemId) const EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:475
bool startEventLoop(CScheduler &scheduler)
Definition: processor.cpp:752
bool isQuorumEstablished() LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:782
std::atomic< uint64_t > round
Keep track of peers and queries sent.
Definition: processor.h:196
static std::unique_ptr< Processor > MakeProcessor(const ArgsManager &argsman, interfaces::Chain &chain, CConnman *connman, ChainstateManager &chainman, CTxMemPool *mempoolIn, CScheduler &scheduler, bilingual_str &error)
Definition: processor.cpp:220
EventLoop eventLoop
Event loop machinery.
Definition: processor.h:240
CTxMemPool * mempool
Definition: processor.h:186
int64_t minAvaproofsNodeCount
Definition: processor.h:249
const bool m_preConsensus
Definition: processor.h:281
Mutex cs_delayedAvahelloNodeIds
Definition: processor.h:261
void runEventLoop() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:1012
Mutex cs_invalidatedBlocks
We don't need many blocks but a low false positive rate.
Definition: processor.h:415
void updatedBlockTip() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:958
RWCollection< VoteMap > voteRecords
Items to run avalanche on.
Definition: processor.h:191
std::unique_ptr< interfaces::Handler > chainNotificationsHandler
Definition: processor.h:257
uint32_t minQuorumScore
Quorum management.
Definition: processor.h:245
void FinalizeNode(const ::Config &config, const CNode &node) override LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Handle removal of a node.
Definition: processor.cpp:950
std::atomic< bool > m_canShareLocalProof
Definition: processor.h:248
bool isAccepted(const AnyVoteItem &item) const
Definition: processor.cpp:447
ProofRef getLocalProof() const
Definition: processor.cpp:742
bool reconcileOrFinalize(const ProofRef &proof) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Wrapper around the addToReconcile for proofs that adds back the finalization flag to the peer if it i...
Definition: processor.cpp:428
const uint32_t staleVoteFactor
Definition: processor.h:254
void sendDelayedAvahello() EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Definition: processor.cpp:725
std::unique_ptr< PeerData > peerData
Definition: processor.h:235
bool eraseStakingRewardWinner(const BlockHash &prevBlockHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards)
Definition: processor.cpp:908
CConnman * connman
Definition: processor.h:184
bool setStakingRewardWinners(const CBlockIndex *pprev, const std::vector< CScript > &winners) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards)
Definition: processor.cpp:937
bool isWorthPolling(const AnyVoteItem &item) const EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:1238
CPubKey getSessionPubKey() const
Definition: processor.cpp:681
Processor(Config avaconfig, interfaces::Chain &chain, CConnman *connmanIn, ChainstateManager &chainman, CTxMemPool *mempoolIn, CScheduler &scheduler, std::unique_ptr< PeerData > peerDataIn, CKey sessionKeyIn, uint32_t minQuorumTotalScoreIn, double minQuorumConnectedScoreRatioIn, int64_t minAvaproofsNodeCountIn, uint32_t staleVoteThresholdIn, uint32_t staleVoteFactorIn, Amount stakeUtxoDustThresholdIn, bool preConsensus)
Definition: processor.cpp:144
ChainstateManager & chainman
Definition: processor.h:185
std::atomic< int64_t > avaproofsNodeCounter
Definition: processor.h:250
bool computeStakingReward(const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:876
ProofRegistrationState getLocalProofRegistrationState() const
Definition: processor.cpp:746
void cleanupStakingRewards(const int minHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards)
Definition: processor.cpp:913
void clearTimedoutRequests() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
Definition: processor.cpp:1080
Mutex cs_peerManager
Keep track of the peers and associated infos.
Definition: processor.h:201
bool getLocalAcceptance(const AnyVoteItem &item) const
Definition: processor.h:458
void avaproofsSent(NodeId nodeid) LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
Definition: processor.cpp:761
double minQuorumConnectedScoreRatio
Definition: processor.h:246
void clearFinalizedItems() EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:479
static bool FromHex(Proof &proof, const std::string &hexProof, bilingual_str &errorOut)
Definition: proof.cpp:51
bool verify(const Amount &stakeUtxoDustThreshold, ProofValidationState &state) const
Definition: proof.cpp:119
static uint32_t amountToScore(Amount amount)
Definition: proof.cpp:100
uint32_t GetError() const
Definition: protocol.h:27
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
Chain notifications.
Definition: chain.h:241
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:123
virtual std::unique_ptr< Handler > handleNotifications(std::shared_ptr< Notifications > notifications)=0
Register handler for notifications.
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
256-bit opaque blob.
Definition: uint256.h:129
static const uint256 ZERO
Definition: uint256.h:134
const Config & GetConfig()
Definition: config.cpp:34
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
std::array< uint8_t, CPubKey::SCHNORR_SIZE > SchnorrSig
a Schnorr signature
Definition: key.h:25
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:77
#define LogPrint(category,...)
Definition: logging.h:210
bool ParseMoney(const std::string &money_string, Amount &nRet)
Parse an amount denoted in full coins.
Definition: moneystr.cpp:37
@ AVALANCHE
Definition: logging.h:62
const char * AVAHELLO
Contains a delegation and a signature.
Definition: protocol.cpp:50
const char * AVARESPONSE
Contains an avalanche::Response.
Definition: protocol.cpp:52
const char * AVAPOLL
Contains an avalanche::Poll.
Definition: protocol.cpp:51
static constexpr Amount PROOF_DUST_THRESHOLD
Minimum amount per utxo.
Definition: proof.h:40
std::map< AnyVoteItem, VoteRecord, VoteMapComparator > VoteMap
Definition: processor.h:172
static bool VerifyDelegation(const Delegation &dg, const CPubKey &expectedPubKey, bilingual_str &error)
Definition: processor.cpp:91
static bool isNull(const AnyVoteItem &item)
Definition: processor.cpp:405
std::variant< const ProofRef, const CBlockIndex *, const CTransactionRef > AnyVoteItem
Definition: processor.h:87
static const uint256 GetVoteItemId(const AnyVoteItem &item)
Definition: processor.cpp:41
static bool VerifyProof(const Amount &stakeUtxoDustThreshold, const Proof &proof, bilingual_str &error)
Definition: processor.cpp:59
RCUPtr< const Proof > ProofRef
Definition: proof.h:185
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
Definition: init.h:28
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:257
static constexpr NodeId NO_NODE
Special NodeId that represent no node.
Definition: nodeid.h:15
int64_t NodeId
Definition: nodeid.h:10
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
static const std::string AVAPEERS_FILE_NAME
Definition: processor.cpp:34
Response response
Definition: processor.cpp:490
static constexpr std::chrono::milliseconds AVALANCHE_TIME_STEP
Run the avalanche event loop every 10ms.
Definition: processor.cpp:32
SchnorrSig sig
Definition: processor.cpp:491
std::unique_ptr< avalanche::Processor > g_avalanche
Global avalanche instance.
Definition: processor.cpp:38
static constexpr std::chrono::milliseconds AVALANCHE_DEFAULT_QUERY_TIMEOUT
How long before we consider that a query timed out.
Definition: processor.h:57
static constexpr size_t AVALANCHE_MAX_ELEMENT_POLL
Maximum item that can be polled at once.
Definition: processor.h:52
static constexpr int AVALANCHE_MAX_PROOF_STAKES
How many UTXOs can be used for a single proof.
Definition: proof.h:29
@ MSG_TX
Definition: protocol.h:565
@ MSG_AVA_PROOF
Definition: protocol.h:572
@ MSG_BLOCK
Definition: protocol.h:566
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:213
@ SER_GETHASH
Definition: serialize.h:154
#define READWRITE(...)
Definition: serialize.h:166
bool IsStakingRewardsActivated(const Consensus::Params &params, const CBlockIndex *pprev)
bool ParseDouble(const std::string &str, double *out)
Convert string to double with strict parse error feedback.
Definition: amount.h:19
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
bool stopEventLoop() EXCLUSIVE_LOCKS_REQUIRED(!cs_running)
Definition: eventloop.cpp:45
bool startEventLoop(CScheduler &scheduler, std::function< void()> runEventLoop, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!cs_running)
Definition: eventloop.cpp:13
A TxId is the identifier of a transaction.
Definition: txid.h:14
const std::chrono::milliseconds queryTimeoutDuration
Definition: config.h:13
bool operator()(const CBlockIndex *pindex) const LOCKS_EXCLUDED(cs_main)
Definition: processor.cpp:1243
bool operator()(const CBlockIndex *pindex) const LOCKS_EXCLUDED(cs_main)
Definition: processor.cpp:1183
ProofRegistrationState proofState GUARDED_BY(cs_proofState)
std::vector< CScript > winners
Definition: processor.h:274
Vote history.
Definition: voterecord.h:49
Bilingual messages:
Definition: translation.h:17
#define AssertLockNotHeld(cs)
Definition: sync.h:163
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
ArgsManager gArgs
Definition: system.cpp:80
bool error(const char *fmt, const Args &...args)
Definition: system.h:45
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
AssertLockHeld(pool.cs)
assert(!tx.IsCoinBase())
static constexpr uint32_t AVALANCHE_VOTE_STALE_FACTOR
Scaling factor applied to confidence to determine staleness threshold.
Definition: voterecord.h:35
static constexpr uint32_t AVALANCHE_VOTE_STALE_MIN_THRESHOLD
Lowest configurable staleness threshold (finalization score + necessary votes to increase confidence ...
Definition: voterecord.h:28
static constexpr uint32_t AVALANCHE_VOTE_STALE_THRESHOLD
Number of votes before a record may be considered as stale.
Definition: voterecord.h:22