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