Bitcoin ABC 0.31.0
P2P Digital Currency
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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
6
13#include <chain.h>
14#include <common/args.h>
15#include <key_io.h> // For DecodeSecret
16#include <net.h>
17#include <netbase.h>
18#include <netmessagemaker.h>
20#include <scheduler.h>
21#include <util/bitmanip.h>
22#include <util/moneystr.h>
23#include <util/time.h>
24#include <util/translation.h>
25#include <validation.h>
26
27#include <chrono>
28#include <limits>
29#include <tuple>
30
34static constexpr std::chrono::milliseconds AVALANCHE_TIME_STEP{10};
35
36static const std::string AVAPEERS_FILE_NAME{"avapeers.dat"};
37
38namespace avalanche {
39static const uint256 GetVoteItemId(const AnyVoteItem &item) {
40 return std::visit(variant::overloaded{
41 [](const ProofRef &proof) {
42 uint256 id = proof->getId();
43 return id;
44 },
45 [](const CBlockIndex *pindex) {
46 uint256 hash = pindex->GetBlockHash();
47 return hash;
48 },
49 [](const StakeContenderId &contenderId) {
50 return uint256(contenderId);
51 },
52 [](const CTransactionRef &tx) {
53 uint256 id = tx->GetId();
54 return id;
55 },
56 },
57 item);
58}
59
60static bool VerifyProof(const Amount &stakeUtxoDustThreshold,
61 const Proof &proof, bilingual_str &error) {
62 ProofValidationState proof_state;
63
64 if (!proof.verify(stakeUtxoDustThreshold, proof_state)) {
65 switch (proof_state.GetResult()) {
67 error = _("The avalanche proof has no stake.");
68 return false;
70 error = _("The avalanche proof stake is too low.");
71 return false;
73 error = _("The avalanche proof has duplicated stake.");
74 return false;
76 error = _("The avalanche proof has invalid stake signatures.");
77 return false;
80 _("The avalanche proof has too many utxos (max: %u)."),
82 return false;
83 default:
84 error = _("The avalanche proof is invalid.");
85 return false;
86 }
87 }
88
89 return true;
90}
91
92static bool VerifyDelegation(const Delegation &dg,
93 const CPubKey &expectedPubKey,
95 DelegationState dg_state;
96
97 CPubKey auth;
98 if (!dg.verify(dg_state, auth)) {
99 switch (dg_state.GetResult()) {
101 error = _("The avalanche delegation has invalid signatures.");
102 return false;
104 error = _(
105 "The avalanche delegation has too many delegation levels.");
106 return false;
107 default:
108 error = _("The avalanche delegation is invalid.");
109 return false;
110 }
111 }
112
113 if (auth != expectedPubKey) {
114 error = _(
115 "The avalanche delegation does not match the expected public key.");
116 return false;
117 }
118
119 return true;
120}
121
125
128};
129
133
134public:
136
138
140 uint64_t mempool_sequence) override {
142 }
143};
144
146 CConnman *connmanIn, ChainstateManager &chainmanIn,
147 CTxMemPool *mempoolIn, CScheduler &scheduler,
148 std::unique_ptr<PeerData> peerDataIn, CKey sessionKeyIn,
149 uint32_t minQuorumTotalScoreIn,
150 double minQuorumConnectedScoreRatioIn,
151 int64_t minAvaproofsNodeCountIn,
152 uint32_t staleVoteThresholdIn, uint32_t staleVoteFactorIn,
153 Amount stakeUtxoDustThreshold, bool preConsensus,
154 bool stakingPreConsensus)
155 : avaconfig(std::move(avaconfigIn)), connman(connmanIn),
156 chainman(chainmanIn), mempool(mempoolIn), round(0),
157 peerManager(std::make_unique<PeerManager>(
158 stakeUtxoDustThreshold, chainman, stakingPreConsensus,
159 peerDataIn ? peerDataIn->proof : ProofRef())),
160 peerData(std::move(peerDataIn)), sessionKey(std::move(sessionKeyIn)),
161 minQuorumScore(minQuorumTotalScoreIn),
162 minQuorumConnectedScoreRatio(minQuorumConnectedScoreRatioIn),
163 minAvaproofsNodeCount(minAvaproofsNodeCountIn),
164 staleVoteThreshold(staleVoteThresholdIn),
165 staleVoteFactor(staleVoteFactorIn), m_preConsensus(preConsensus),
166 m_stakingPreConsensus(stakingPreConsensus) {
167 // Make sure we get notified of chain state changes.
169 chain.handleNotifications(std::make_shared<NotificationsHandler>(this));
170
171 scheduler.scheduleEvery(
172 [this]() -> bool {
173 std::unordered_set<ProofRef, SaltedProofHasher> registeredProofs;
175 peerManager->cleanupDanglingProofs(registeredProofs));
176 for (const auto &proof : registeredProofs) {
178 "Promoting previously dangling proof %s\n",
179 proof->getId().ToString());
180 reconcileOrFinalize(proof);
181 }
182 return true;
183 },
184 5min);
185
186 if (!gArgs.GetBoolArg("-persistavapeers", DEFAULT_PERSIST_AVAPEERS)) {
187 return;
188 }
189
190 std::unordered_set<ProofRef, SaltedProofHasher> registeredProofs;
191
192 // Attempt to load the peer file if it exists.
193 const fs::path dumpPath = gArgs.GetDataDirNet() / AVAPEERS_FILE_NAME;
194 WITH_LOCK(cs_peerManager, return peerManager->loadPeersFromFile(
195 dumpPath, registeredProofs));
196
197 // We just loaded the previous finalization status, but make sure to trigger
198 // another round of vote for these proofs to avoid issue if the network
199 // status changed since the peers file was dumped.
200 for (const auto &proof : registeredProofs) {
201 addToReconcile(proof);
202 }
203
204 LogPrint(BCLog::AVALANCHE, "Loaded %d peers from the %s file\n",
205 registeredProofs.size(), PathToString(dumpPath));
206}
207
211
212 if (!gArgs.GetBoolArg("-persistavapeers", DEFAULT_PERSIST_AVAPEERS)) {
213 return;
214 }
215
217 // Discard the status output: if it fails we want to continue normally.
218 peerManager->dumpPeersToFile(gArgs.GetDataDirNet() / AVAPEERS_FILE_NAME);
219}
220
221std::unique_ptr<Processor>
223 CConnman *connman, ChainstateManager &chainman,
224 CTxMemPool *mempool, CScheduler &scheduler,
226 std::unique_ptr<PeerData> peerData;
227 CKey masterKey;
229
230 Amount stakeUtxoDustThreshold = PROOF_DUST_THRESHOLD;
231 if (argsman.IsArgSet("-avaproofstakeutxodustthreshold") &&
232 !ParseMoney(argsman.GetArg("-avaproofstakeutxodustthreshold", ""),
233 stakeUtxoDustThreshold)) {
234 error = _("The avalanche stake utxo dust threshold amount is invalid.");
235 return nullptr;
236 }
237
238 if (argsman.IsArgSet("-avasessionkey")) {
239 sessionKey = DecodeSecret(argsman.GetArg("-avasessionkey", ""));
240 if (!sessionKey.IsValid()) {
241 error = _("The avalanche session key is invalid.");
242 return nullptr;
243 }
244 } else {
245 // Pick a random key for the session.
247 }
248
249 if (argsman.IsArgSet("-avaproof")) {
250 if (!argsman.IsArgSet("-avamasterkey")) {
251 error = _(
252 "The avalanche master key is missing for the avalanche proof.");
253 return nullptr;
254 }
255
256 masterKey = DecodeSecret(argsman.GetArg("-avamasterkey", ""));
257 if (!masterKey.IsValid()) {
258 error = _("The avalanche master key is invalid.");
259 return nullptr;
260 }
261
262 auto proof = RCUPtr<Proof>::make();
263 if (!Proof::FromHex(*proof, argsman.GetArg("-avaproof", ""), error)) {
264 // error is set by FromHex
265 return nullptr;
266 }
267
268 peerData = std::make_unique<PeerData>();
269 peerData->proof = proof;
270 if (!VerifyProof(stakeUtxoDustThreshold, *peerData->proof, error)) {
271 // error is set by VerifyProof
272 return nullptr;
273 }
274
275 std::unique_ptr<DelegationBuilder> dgb;
276 const CPubKey &masterPubKey = masterKey.GetPubKey();
277
278 if (argsman.IsArgSet("-avadelegation")) {
279 Delegation dg;
280 if (!Delegation::FromHex(dg, argsman.GetArg("-avadelegation", ""),
281 error)) {
282 // error is set by FromHex()
283 return nullptr;
284 }
285
286 if (dg.getProofId() != peerData->proof->getId()) {
287 error = _("The delegation does not match the proof.");
288 return nullptr;
289 }
290
291 if (masterPubKey != dg.getDelegatedPubkey()) {
292 error = _(
293 "The master key does not match the delegation public key.");
294 return nullptr;
295 }
296
297 dgb = std::make_unique<DelegationBuilder>(dg);
298 } else {
299 if (masterPubKey != peerData->proof->getMaster()) {
300 error =
301 _("The master key does not match the proof public key.");
302 return nullptr;
303 }
304
305 dgb = std::make_unique<DelegationBuilder>(*peerData->proof);
306 }
307
308 // Generate the delegation to the session key.
309 const CPubKey sessionPubKey = sessionKey.GetPubKey();
310 if (sessionPubKey != masterPubKey) {
311 if (!dgb->addLevel(masterKey, sessionPubKey)) {
312 error = _("Failed to generate a delegation for this session.");
313 return nullptr;
314 }
315 }
316 peerData->delegation = dgb->build();
317
318 if (!VerifyDelegation(peerData->delegation, sessionPubKey, error)) {
319 // error is set by VerifyDelegation
320 return nullptr;
321 }
322 }
323
324 const auto queryTimeoutDuration =
325 std::chrono::milliseconds(argsman.GetIntArg(
326 "-avatimeout", AVALANCHE_DEFAULT_QUERY_TIMEOUT.count()));
327
328 // Determine quorum parameters
330 if (argsman.IsArgSet("-avaminquorumstake") &&
331 !ParseMoney(argsman.GetArg("-avaminquorumstake", ""), minQuorumStake)) {
332 error = _("The avalanche min quorum stake amount is invalid.");
333 return nullptr;
334 }
335
336 if (!MoneyRange(minQuorumStake)) {
337 error = _("The avalanche min quorum stake amount is out of range.");
338 return nullptr;
339 }
340
341 double minQuorumConnectedStakeRatio =
343 if (argsman.IsArgSet("-avaminquorumconnectedstakeratio")) {
344 // Parse the parameter with a precision of 0.000001.
345 int64_t megaMinRatio;
346 if (!ParseFixedPoint(
347 argsman.GetArg("-avaminquorumconnectedstakeratio", ""), 6,
348 &megaMinRatio)) {
349 error =
350 _("The avalanche min quorum connected stake ratio is invalid.");
351 return nullptr;
352 }
353 minQuorumConnectedStakeRatio = double(megaMinRatio) / 1000000;
354 }
355
356 if (minQuorumConnectedStakeRatio < 0 || minQuorumConnectedStakeRatio > 1) {
357 error = _(
358 "The avalanche min quorum connected stake ratio is out of range.");
359 return nullptr;
360 }
361
362 int64_t minAvaproofsNodeCount =
363 argsman.GetIntArg("-avaminavaproofsnodecount",
365 if (minAvaproofsNodeCount < 0) {
366 error = _("The minimum number of node that sent avaproofs message "
367 "should be non-negative");
368 return nullptr;
369 }
370
371 // Determine voting parameters
372 int64_t staleVoteThreshold = argsman.GetIntArg(
373 "-avastalevotethreshold", AVALANCHE_VOTE_STALE_THRESHOLD);
375 error = strprintf(_("The avalanche stale vote threshold must be "
376 "greater than or equal to %d"),
378 return nullptr;
379 }
380 if (staleVoteThreshold > std::numeric_limits<uint32_t>::max()) {
381 error = strprintf(_("The avalanche stale vote threshold must be less "
382 "than or equal to %d"),
383 std::numeric_limits<uint32_t>::max());
384 return nullptr;
385 }
386
387 int64_t staleVoteFactor =
388 argsman.GetIntArg("-avastalevotefactor", AVALANCHE_VOTE_STALE_FACTOR);
389 if (staleVoteFactor <= 0) {
390 error = _("The avalanche stale vote factor must be greater than 0");
391 return nullptr;
392 }
393 if (staleVoteFactor > std::numeric_limits<uint32_t>::max()) {
394 error = strprintf(_("The avalanche stale vote factor must be less than "
395 "or equal to %d"),
396 std::numeric_limits<uint32_t>::max());
397 return nullptr;
398 }
399
400 Config avaconfig(queryTimeoutDuration);
401
402 // We can't use std::make_unique with a private constructor
403 return std::unique_ptr<Processor>(new Processor(
404 std::move(avaconfig), chain, connman, chainman, mempool, scheduler,
405 std::move(peerData), std::move(sessionKey),
406 Proof::amountToScore(minQuorumStake), minQuorumConnectedStakeRatio,
408 stakeUtxoDustThreshold,
409 argsman.GetBoolArg("-avalanchepreconsensus",
411 argsman.GetBoolArg("-avalanchestakingpreconsensus",
413}
414
415static bool isNull(const AnyVoteItem &item) {
416 return item.valueless_by_exception() ||
417 std::visit(variant::overloaded{
418 [](const StakeContenderId &contenderId) {
419 return contenderId == uint256::ZERO;
420 },
421 [](const auto &item) { return item == nullptr; },
422 },
423 item);
424};
425
427 if (isNull(item)) {
428 return false;
429 }
430
431 if (!isWorthPolling(item)) {
432 return false;
433 }
434
435 // getLocalAcceptance() takes the voteRecords read lock, so we can't inline
436 // the calls or we get a deadlock.
437 const bool accepted = getLocalAcceptance(item);
438
440 ->insert(std::make_pair(item, VoteRecord(accepted)))
441 .second;
442}
443
445 if (!proof) {
446 return false;
447 }
448
449 if (isRecentlyFinalized(proof->getId())) {
450 PeerId peerid;
452 if (peerManager->forPeer(proof->getId(), [&](const Peer &peer) {
453 peerid = peer.peerid;
454 return true;
455 })) {
456 return peerManager->setFinalized(peerid);
457 }
458 }
459
460 return addToReconcile(proof);
461}
462
463bool Processor::isAccepted(const AnyVoteItem &item) const {
464 if (isNull(item)) {
465 return false;
466 }
467
468 auto r = voteRecords.getReadView();
469 auto it = r->find(item);
470 if (it == r.end()) {
471 return false;
472 }
473
474 return it->second.isAccepted();
475}
476
477int Processor::getConfidence(const AnyVoteItem &item) const {
478 if (isNull(item)) {
479 return -1;
480 }
481
482 auto r = voteRecords.getReadView();
483 auto it = r->find(item);
484 if (it == r.end()) {
485 return -1;
486 }
487
488 return it->second.getConfidence();
489}
490
491bool Processor::isRecentlyFinalized(const uint256 &itemId) const {
492 return WITH_LOCK(cs_finalizedItems, return finalizedItems.contains(itemId));
493}
494
496 WITH_LOCK(cs_finalizedItems, finalizedItems.insert(itemId));
497}
498
501 finalizedItems.reset();
502}
503
504namespace {
509 class TCPResponse {
510 Response response;
512
513 public:
514 TCPResponse(Response responseIn, const CKey &key)
515 : response(std::move(responseIn)) {
516 HashWriter hasher{};
517 hasher << response;
518 const uint256 hash = hasher.GetHash();
519
520 // Now let's sign!
521 if (!key.SignSchnorr(hash, sig)) {
522 sig.fill(0);
523 }
524 }
525
526 // serialization support
527 SERIALIZE_METHODS(TCPResponse, obj) {
528 READWRITE(obj.response, obj.sig);
529 }
530 };
531} // namespace
532
535 pfrom, CNetMsgMaker(pfrom->GetCommonVersion())
537 TCPResponse(std::move(response), sessionKey)));
538}
539
541 std::vector<VoteItemUpdate> &updates,
542 int &banscore, std::string &error) {
543 updates.clear();
544 {
545 // Save the time at which we can query again.
547
548 // FIXME: This will override the time even when we received an old stale
549 // message. This should check that the message is indeed the most up to
550 // date one before updating the time.
551 peerManager->updateNextRequestTime(
552 nodeid, Now<SteadyMilliseconds>() +
553 std::chrono::milliseconds(response.getCooldown()));
554 }
555
556 std::vector<CInv> invs;
557
558 {
559 // Check that the query exists. There is a possibility that it has been
560 // deleted if the query timed out, so we don't increase the ban score to
561 // slowly banning nodes for poor networking over time. Banning has to be
562 // handled at callsite to avoid DoS.
563 auto w = queries.getWriteView();
564 auto it = w->find(std::make_tuple(nodeid, response.getRound()));
565 if (it == w.end()) {
566 banscore = 0;
567 error = "unexpected-ava-response";
568 return false;
569 }
570
571 invs = std::move(it->invs);
572 w->erase(it);
573 }
574
575 // Verify that the request and the vote are consistent.
576 const std::vector<Vote> &votes = response.GetVotes();
577 size_t size = invs.size();
578 if (votes.size() != size) {
579 banscore = 100;
580 error = "invalid-ava-response-size";
581 return false;
582 }
583
584 for (size_t i = 0; i < size; i++) {
585 if (invs[i].hash != votes[i].GetHash()) {
586 banscore = 100;
587 error = "invalid-ava-response-content";
588 return false;
589 }
590 }
591
592 std::map<AnyVoteItem, Vote, VoteMapComparator> responseItems;
593
594 // At this stage we are certain that invs[i] matches votes[i], so we can use
595 // the inv type to retrieve what is being voted on.
596 for (size_t i = 0; i < size; i++) {
597 auto item = getVoteItemFromInv(invs[i]);
598
599 if (isNull(item)) {
600 // This should not happen, but just in case...
601 continue;
602 }
603
604 if (!isWorthPolling(item)) {
605 // There is no point polling this item.
606 continue;
607 }
608
609 responseItems.insert(std::make_pair(std::move(item), votes[i]));
610 }
611
612 auto voteRecordsWriteView = voteRecords.getWriteView();
613
614 // Register votes.
615 for (const auto &p : responseItems) {
616 auto item = p.first;
617 const Vote &v = p.second;
618
619 auto it = voteRecordsWriteView->find(item);
620 if (it == voteRecordsWriteView.end()) {
621 // We are not voting on that item anymore.
622 continue;
623 }
624
625 auto &vr = it->second;
626 if (!vr.registerVote(nodeid, v.GetError())) {
627 if (vr.isStale(staleVoteThreshold, staleVoteFactor)) {
628 updates.emplace_back(std::move(item), VoteStatus::Stale);
629
630 // Just drop stale votes. If we see this item again, we'll
631 // do a new vote.
632 voteRecordsWriteView->erase(it);
633 }
634 // This vote did not provide any extra information, move on.
635 continue;
636 }
637
638 if (!vr.hasFinalized()) {
639 // This item has not been finalized, so we have nothing more to
640 // do.
641 updates.emplace_back(std::move(item), vr.isAccepted()
644 continue;
645 }
646
647 // We just finalized a vote. If it is valid, then let the caller
648 // know. Either way, remove the item from the map.
649 updates.emplace_back(std::move(item), vr.isAccepted()
652 voteRecordsWriteView->erase(it);
653 }
654
655 // FIXME This doesn't belong here as it has nothing to do with vote
656 // registration.
657 for (const auto &update : updates) {
658 if (update.getStatus() != VoteStatus::Finalized &&
659 update.getStatus() != VoteStatus::Invalid) {
660 continue;
661 }
662
663 const auto &item = update.getVoteItem();
664
665 if (!std::holds_alternative<const CBlockIndex *>(item)) {
666 continue;
667 }
668
669 if (update.getStatus() == VoteStatus::Invalid) {
670 // Track invalidated blocks. Other invalidated types are not
671 // tracked because they may be rejected for transient reasons
672 // (ex: immature proofs or orphaned txs) With blocks this is not
673 // the case. A rejected block will not be mined on. To prevent
674 // reorgs, invalidated blocks should never be polled again.
676 invalidatedBlocks.insert(GetVoteItemId(item));
677 continue;
678 }
679
680 // At this point the block index can only be finalized
681 const CBlockIndex *pindex = std::get<const CBlockIndex *>(item);
683 if (finalizationTip &&
684 finalizationTip->GetAncestor(pindex->nHeight) == pindex) {
685 continue;
686 }
687
688 finalizationTip = pindex;
689 }
690
691 return true;
692}
693
695 return sessionKey.GetPubKey();
696}
697
700
701 Delegation delegation;
702 if (peerData) {
703 if (!canShareLocalProof()) {
704 if (!delayedAvahelloNodeIds.emplace(pfrom->GetId()).second) {
705 // Nothing to do
706 return false;
707 }
708 } else {
709 delegation = peerData->delegation;
710 }
711 }
712
713 HashWriter hasher{};
714 hasher << delegation.getId();
715 hasher << pfrom->GetLocalNonce();
716 hasher << pfrom->nRemoteHostNonce;
717 hasher << pfrom->GetLocalExtraEntropy();
718 hasher << pfrom->nRemoteExtraEntropy;
719
720 // Now let's sign!
722 if (!sessionKey.SignSchnorr(hasher.GetHash(), sig)) {
723 return false;
724 }
725
727 pfrom, CNetMsgMaker(pfrom->GetCommonVersion())
728 .Make(NetMsgType::AVAHELLO, Hello(delegation, sig)));
729
730 return delegation.getLimitedProofId() != uint256::ZERO;
731}
732
735 return sendHelloInternal(pfrom));
736}
737
740
741 auto it = delayedAvahelloNodeIds.begin();
742 while (it != delayedAvahelloNodeIds.end()) {
743 if (connman->ForNode(*it, [&](CNode *pnode) EXCLUSIVE_LOCKS_REQUIRED(
745 return sendHelloInternal(pnode);
746 })) {
747 // Our proof has been announced to this node
748 it = delayedAvahelloNodeIds.erase(it);
749 } else {
750 ++it;
751 }
752 }
753}
754
756 return peerData ? peerData->proof : ProofRef();
757}
758
760 return peerData
761 ? WITH_LOCK(peerData->cs_proofState, return peerData->proofState)
763}
764
767 scheduler, [this]() { this->runEventLoop(); }, AVALANCHE_TIME_STEP);
768}
769
771 return eventLoop.stopEventLoop();
772}
773
776
778 // Before IBD is complete there is no way to make sure a proof is valid
779 // or not, e.g. it can be spent in a block we don't know yet. In order
780 // to increase confidence that our proof set is similar to other nodes
781 // on the network, the messages received during IBD are not accounted.
782 return;
783 }
784
786 if (peerManager->latchAvaproofsSent(nodeid)) {
788 }
789}
790
791/*
792 * Returns a bool indicating whether we have a usable Avalanche quorum enabling
793 * us to take decisions based on polls.
794 */
797
798 {
800 if (peerManager->getNodeCount() < 8) {
801 // There is no point polling if we know the vote cannot converge
802 return false;
803 }
804 }
805
806 /*
807 * The following parameters can naturally go temporarly below the threshold
808 * under normal circumstances, like during a proof replacement with a lower
809 * stake amount, or the discovery of a new proofs for which we don't have a
810 * node yet.
811 * In order to prevent our node from starting and stopping the polls
812 * spuriously on such event, the quorum establishement is latched. The only
813 * parameters that should not latched is the minimum node count, as this
814 * would cause the poll to be inconclusive anyway and should not happen
815 * under normal circumstances.
816 */
818 return true;
819 }
820
821 // Don't do Avalanche while node is IBD'ing
823 return false;
824 }
825
827 return false;
828 }
829
830 auto localProof = getLocalProof();
831
832 // Get the registered proof score and registered score we have nodes for
833 uint32_t totalPeersScore;
834 uint32_t connectedPeersScore;
835 {
837 totalPeersScore = peerManager->getTotalPeersScore();
838 connectedPeersScore = peerManager->getConnectedPeersScore();
839
840 // Consider that we are always connected to our proof, even if we are
841 // the single node using that proof.
842 if (localProof &&
843 peerManager->forPeer(localProof->getId(), [](const Peer &peer) {
844 return peer.node_count == 0;
845 })) {
846 connectedPeersScore += localProof->getScore();
847 }
848 }
849
850 // Ensure enough is being staked overall
851 if (totalPeersScore < minQuorumScore) {
852 return false;
853 }
854
855 // Ensure we have connected score for enough of the overall score
856 uint32_t minConnectedScore =
857 std::round(double(totalPeersScore) * minQuorumConnectedScoreRatio);
858 if (connectedPeersScore < minConnectedScore) {
859 return false;
860 }
861
862 quorumIsEstablished = true;
863
864 // Attempt to compute the staking rewards winner now so we don't have to
865 // wait for a block if we already have all the prerequisites.
866 const CBlockIndex *pprev = WITH_LOCK(cs_main, return chainman.ActiveTip());
867 if (pprev && IsStakingRewardsActivated(chainman.GetConsensus(), pprev)) {
869 }
870
871 return true;
872}
873
875 // The flag is latched
877 return true;
878 }
879
880 // Don't share our proof if we don't have any inbound connection.
881 // This is a best effort measure to prevent advertising a proof if we have
882 // limited network connectivity.
884
886}
887
889 if (!pindex) {
890 return false;
891 }
892
893 // If the quorum is not established there is no point picking a winner that
894 // will be rejected.
895 if (!isQuorumEstablished()) {
896 return false;
897 }
898
899 {
901 if (stakingRewards.count(pindex->GetBlockHash()) > 0) {
902 return true;
903 }
904 }
905
906 StakingReward _stakingRewards;
907 _stakingRewards.blockheight = pindex->nHeight;
908
909 bool rewardsInserted = false;
910 if (WITH_LOCK(cs_peerManager, return peerManager->selectStakingRewardWinner(
911 pindex, _stakingRewards.winners))) {
913 rewardsInserted =
914 stakingRewards
915 .emplace(pindex->GetBlockHash(), std::move(_stakingRewards))
916 .second;
917 }
918
920 // If pindex has not been promoted in the contender cache yet, this will
921 // be a no-op.
922 std::vector<StakeContenderId> pollableContenders;
923 if (setContenderStatusForLocalWinners(pindex, pollableContenders)) {
924 for (const StakeContenderId &contender : pollableContenders) {
925 addToReconcile(contender);
926 }
927 }
928 }
929
930 return rewardsInserted;
931}
932
935 return stakingRewards.erase(prevBlockHash) > 0;
936}
937
938void Processor::cleanupStakingRewards(const int minHeight) {
939 {
941 // std::erase_if is only defined since C++20
942 for (auto it = stakingRewards.begin(); it != stakingRewards.end();) {
943 if (it->second.blockheight < minHeight) {
944 it = stakingRewards.erase(it);
945 } else {
946 ++it;
947 }
948 }
949 }
950
953 return peerManager->cleanupStakeContenders(minHeight));
954 }
955}
956
958 const BlockHash &prevBlockHash,
959 std::vector<std::pair<ProofId, CScript>> &winners) const {
961 auto it = stakingRewards.find(prevBlockHash);
962 if (it == stakingRewards.end()) {
963 return false;
964 }
965
966 winners = it->second.winners;
967 return true;
968}
969
971 std::vector<CScript> &payouts) const {
972 std::vector<std::pair<ProofId, CScript>> winners;
973 if (!getStakingRewardWinners(prevBlockHash, winners)) {
974 return false;
975 }
976
977 payouts.clear();
978 payouts.reserve(winners.size());
979 for (auto &winner : winners) {
980 payouts.push_back(std::move(winner.second));
981 }
982
983 return true;
984}
985
987 const std::vector<CScript> &payouts) {
988 assert(pprev);
989
990 StakingReward stakingReward;
991 stakingReward.blockheight = pprev->nHeight;
992
993 stakingReward.winners.reserve(payouts.size());
994 for (const CScript &payout : payouts) {
995 stakingReward.winners.push_back({ProofId(), payout});
996 }
997
1000 peerManager->setStakeContenderWinners(pprev, payouts);
1001 }
1002
1004 return stakingRewards.insert_or_assign(pprev->GetBlockHash(), stakingReward)
1005 .second;
1006}
1007
1009 const CBlockIndex *pprev,
1010 const std::vector<std::pair<ProofId, CScript>> &winners) {
1011 assert(pprev);
1012
1013 StakingReward stakingReward;
1014 stakingReward.blockheight = pprev->nHeight;
1015 stakingReward.winners = winners;
1016
1018 return stakingRewards.insert_or_assign(pprev->GetBlockHash(), stakingReward)
1019 .second;
1020}
1021
1022void Processor::FinalizeNode(const ::Config &config, const CNode &node) {
1024
1025 const NodeId nodeid = node.GetId();
1026 WITH_LOCK(cs_peerManager, peerManager->removeNode(nodeid));
1027 WITH_LOCK(cs_delayedAvahelloNodeIds, delayedAvahelloNodeIds.erase(nodeid));
1028}
1029
1031 const StakeContenderId &contenderId) const {
1034
1035 BlockHash prevblockhash;
1036 int status =
1037 WITH_LOCK(cs_peerManager, return peerManager->getStakeContenderStatus(
1038 contenderId, prevblockhash));
1039
1040 if (status != -1) {
1041 std::vector<std::pair<ProofId, CScript>> winners;
1042 getStakingRewardWinners(prevblockhash, winners);
1043 if (winners.size() == 0) {
1044 // If we have not selected a local staking rewards winner yet,
1045 // indicate this contender is pending to avoid convergence issues.
1046 return -2;
1047 }
1048 }
1049
1050 return status;
1051}
1052
1055 peerManager->acceptStakeContender(contenderId);
1056}
1057
1060
1061 BlockHash prevblockhash;
1062 std::vector<std::pair<ProofId, CScript>> winners;
1063 {
1065 peerManager->finalizeStakeContender(contenderId, prevblockhash,
1066 winners);
1067 }
1068
1069 // Set staking rewards to include newly finalized contender
1070 if (winners.size() > 0) {
1071 const CBlockIndex *block = WITH_LOCK(
1072 cs_main,
1073 return chainman.m_blockman.LookupBlockIndex(prevblockhash));
1074 if (block) {
1075 setStakingRewardWinners(block, winners);
1076 }
1077 }
1078}
1079
1082 peerManager->rejectStakeContender(contenderId);
1083}
1084
1086 const CBlockIndex *activeTip =
1088 assert(activeTip);
1089
1090 if (!hasFinalizedTip()) {
1091 // Avoid growing the contender cache until we have finalized a block
1092 return;
1093 }
1094
1095 {
1097 peerManager->promoteStakeContendersToBlock(activeTip);
1098 }
1099
1100 // If staking rewards have not been computed yet, we will try again when
1101 // they have been.
1102 std::vector<StakeContenderId> pollableContenders;
1103 if (setContenderStatusForLocalWinners(activeTip, pollableContenders)) {
1104 for (const StakeContenderId &contender : pollableContenders) {
1105 addToReconcile(contender);
1106 }
1107 }
1108}
1109
1111 const CBlockIndex *pindex,
1112 std::vector<StakeContenderId> &pollableContenders) {
1113 const BlockHash prevblockhash = pindex->GetBlockHash();
1114 std::vector<std::pair<ProofId, CScript>> winners;
1115 getStakingRewardWinners(prevblockhash, winners);
1116 if (winners.size() == 0) {
1117 // Staking rewards not computed yet
1118 return false;
1119 }
1120
1122 return peerManager->setContenderStatusForLocalWinners(
1123 prevblockhash, winners, AVALANCHE_CONTENDER_MAX_POLLABLE,
1124 pollableContenders);
1125}
1126
1128 const bool registerLocalProof = canShareLocalProof();
1129 auto registerProofs = [&]() {
1131
1132 auto registeredProofs = peerManager->updatedBlockTip();
1133
1134 ProofRegistrationState localProofState;
1135 if (peerData && peerData->proof && registerLocalProof) {
1136 if (peerManager->registerProof(peerData->proof, localProofState)) {
1137 registeredProofs.insert(peerData->proof);
1138 }
1139
1140 if (localProofState.GetResult() ==
1142 // If our proof already exists, that's fine but we don't want to
1143 // erase the state with a duplicated proof status, so let's
1144 // retrieve the proper state. It also means we are able to
1145 // update the status should the proof move from one pool to the
1146 // other.
1147 const ProofId &localProofId = peerData->proof->getId();
1148 if (peerManager->isImmature(localProofId)) {
1150 "immature-proof");
1151 }
1152 if (peerManager->isInConflictingPool(localProofId)) {
1153 localProofState.Invalid(
1155 "conflicting-utxos");
1156 }
1157 if (peerManager->isBoundToPeer(localProofId)) {
1158 localProofState = ProofRegistrationState();
1159 }
1160 }
1161
1162 WITH_LOCK(peerData->cs_proofState,
1163 peerData->proofState = std::move(localProofState));
1164 }
1165
1166 return registeredProofs;
1167 };
1168
1169 auto registeredProofs = registerProofs();
1170 for (const auto &proof : registeredProofs) {
1171 reconcileOrFinalize(proof);
1172 }
1173
1176 }
1177}
1178
1180 if (m_preConsensus) {
1181 addToReconcile(tx);
1182 }
1183}
1184
1186 // Don't poll if quorum hasn't been established yet
1187 if (!isQuorumEstablished()) {
1188 return;
1189 }
1190
1191 // First things first, check if we have requests that timed out and clear
1192 // them.
1194
1195 // Make sure there is at least one suitable node to query before gathering
1196 // invs.
1197 NodeId nodeid = WITH_LOCK(cs_peerManager, return peerManager->selectNode());
1198 if (nodeid == NO_NODE) {
1199 return;
1200 }
1201 std::vector<CInv> invs = getInvsForNextPoll();
1202 if (invs.empty()) {
1203 return;
1204 }
1205
1207
1208 do {
1214 bool hasSent = connman->ForNode(
1215 nodeid, [this, &invs](CNode *pnode) EXCLUSIVE_LOCKS_REQUIRED(
1217 uint64_t current_round = round++;
1218
1219 {
1220 // Compute the time at which this requests times out.
1221 auto timeout = Now<SteadyMilliseconds>() +
1223 // Register the query.
1224 queries.getWriteView()->insert(
1225 {pnode->GetId(), current_round, timeout, invs});
1226 // Set the timeout.
1227 peerManager->updateNextRequestTime(pnode->GetId(), timeout);
1228 }
1229
1230 pnode->invsPolled(invs.size());
1231
1232 // Send the query to the node.
1234 pnode, CNetMsgMaker(pnode->GetCommonVersion())
1236 Poll(current_round, std::move(invs))));
1237 return true;
1238 });
1239
1240 // Success!
1241 if (hasSent) {
1242 return;
1243 }
1244
1245 // This node is obsolete, delete it.
1246 peerManager->removeNode(nodeid);
1247
1248 // Get next suitable node to try again
1249 nodeid = peerManager->selectNode();
1250 } while (nodeid != NO_NODE);
1251}
1252
1254 auto now = Now<SteadyMilliseconds>();
1255 std::map<CInv, uint8_t> timedout_items{};
1256
1257 {
1258 // Clear expired requests.
1259 auto w = queries.getWriteView();
1260 auto it = w->get<query_timeout>().begin();
1261 while (it != w->get<query_timeout>().end() && it->timeout < now) {
1262 for (const auto &i : it->invs) {
1263 timedout_items[i]++;
1264 }
1265
1266 w->get<query_timeout>().erase(it++);
1267 }
1268 }
1269
1270 if (timedout_items.empty()) {
1271 return;
1272 }
1273
1274 // In flight request accounting.
1275 auto voteRecordsWriteView = voteRecords.getWriteView();
1276 for (const auto &p : timedout_items) {
1277 auto item = getVoteItemFromInv(p.first);
1278
1279 if (isNull(item)) {
1280 continue;
1281 }
1282
1283 auto it = voteRecordsWriteView->find(item);
1284 if (it == voteRecordsWriteView.end()) {
1285 continue;
1286 }
1287
1288 it->second.clearInflightRequest(p.second);
1289 }
1290}
1291
1292std::vector<CInv> Processor::getInvsForNextPoll(bool forPoll) {
1293 std::vector<CInv> invs;
1294
1295 {
1296 // First remove all items that are not worth polling.
1297 auto w = voteRecords.getWriteView();
1298 for (auto it = w->begin(); it != w->end();) {
1299 if (!isWorthPolling(it->first)) {
1300 it = w->erase(it);
1301 } else {
1302 ++it;
1303 }
1304 }
1305 }
1306
1307 auto buildInvFromVoteItem = variant::overloaded{
1308 [](const ProofRef &proof) {
1309 return CInv(MSG_AVA_PROOF, proof->getId());
1310 },
1311 [](const CBlockIndex *pindex) {
1312 return CInv(MSG_BLOCK, pindex->GetBlockHash());
1313 },
1314 [](const StakeContenderId &contenderId) {
1315 return CInv(MSG_AVA_STAKE_CONTENDER, contenderId);
1316 },
1317 [](const CTransactionRef &tx) { return CInv(MSG_TX, tx->GetHash()); },
1318 };
1319
1320 auto r = voteRecords.getReadView();
1321 for (const auto &[item, voteRecord] : r) {
1322 if (invs.size() >= AVALANCHE_MAX_ELEMENT_POLL) {
1323 // Make sure we do not produce more invs than specified by the
1324 // protocol.
1325 return invs;
1326 }
1327
1328 const bool shouldPoll =
1329 forPoll ? voteRecord.registerPoll() : voteRecord.shouldPoll();
1330
1331 if (!shouldPoll) {
1332 continue;
1333 }
1334
1335 invs.emplace_back(std::visit(buildInvFromVoteItem, item));
1336 }
1337
1338 return invs;
1339}
1340
1342 if (inv.IsMsgBlk()) {
1344 BlockHash(inv.hash)));
1345 }
1346
1347 if (inv.IsMsgProof()) {
1349 return peerManager->getProof(ProofId(inv.hash)));
1350 }
1351
1352 if (inv.IsMsgStakeContender()) {
1353 return StakeContenderId(inv.hash);
1354 }
1355
1356 if (mempool && inv.IsMsgTx()) {
1357 LOCK(mempool->cs);
1358 if (CTransactionRef tx = mempool->get(TxId(inv.hash))) {
1359 return tx;
1360 }
1362 [&inv](const TxConflicting &conflicting) {
1363 return conflicting.GetTx(TxId(inv.hash));
1364 })) {
1365 return tx;
1366 }
1367 }
1368
1369 return {nullptr};
1370}
1371
1374
1375 LOCK(cs_main);
1376
1377 if (pindex->nStatus.isInvalid()) {
1378 // No point polling invalid blocks.
1379 return false;
1380 }
1381
1383 return processor.finalizationTip &&
1384 processor.finalizationTip->GetAncestor(
1385 pindex->nHeight) == pindex)) {
1386 // There is no point polling blocks that are ancestor of a block that
1387 // has been accepted by the network.
1388 return false;
1389 }
1390
1392 return processor.invalidatedBlocks.contains(
1393 pindex->GetBlockHash()))) {
1394 // Blocks invalidated by Avalanche should not be polled twice.
1395 return false;
1396 }
1397
1398 return true;
1399}
1400
1402 // Avoid lock order issues cs_main -> cs_peerManager
1404 AssertLockNotHeld(processor.cs_peerManager);
1405
1406 const ProofId &proofid = proof->getId();
1407
1408 LOCK(processor.cs_peerManager);
1409
1410 // No point polling immature or discarded proofs
1411 return processor.peerManager->isBoundToPeer(proofid) ||
1412 processor.peerManager->isInConflictingPool(proofid);
1413}
1414
1416 const StakeContenderId &contenderId) const {
1417 AssertLockNotHeld(processor.cs_peerManager);
1418 AssertLockNotHeld(processor.cs_stakingRewards);
1419
1420 // Only worth polling for contenders that we know about
1421 return processor.getStakeContenderStatus(contenderId) != -1;
1422}
1423
1425 if (!processor.mempool) {
1426 return false;
1427 }
1428
1429 AssertLockNotHeld(processor.mempool->cs);
1430 return WITH_LOCK(processor.mempool->cs,
1431 return processor.mempool->isWorthPolling(tx));
1432}
1433
1435 return !isRecentlyFinalized(GetVoteItemId(item)) &&
1436 std::visit(IsWorthPolling(*this), item);
1437}
1438
1440 const CBlockIndex *pindex) const {
1442
1443 return WITH_LOCK(cs_main,
1444 return processor.chainman.ActiveChain().Contains(pindex));
1445}
1446
1448 AssertLockNotHeld(processor.cs_peerManager);
1449
1450 return WITH_LOCK(
1451 processor.cs_peerManager,
1452 return processor.peerManager->isBoundToPeer(proof->getId()));
1453}
1454
1456 const StakeContenderId &contenderId) const {
1457 AssertLockNotHeld(processor.cs_peerManager);
1458 AssertLockNotHeld(processor.cs_stakingRewards);
1459
1460 return processor.getStakeContenderStatus(contenderId) == 0;
1461}
1462
1464 const CTransactionRef &tx) const {
1465 if (!processor.mempool) {
1466 return false;
1467 }
1468
1469 AssertLockNotHeld(processor.mempool->cs);
1470
1471 return WITH_LOCK(processor.mempool->cs,
1472 return processor.mempool->exists(tx->GetId()));
1473}
1474
1475} // 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 bool DEFAULT_AVALANCHE_STAKING_PRECONSENSUS
Default for -avalanchestakingpreconsensus.
Definition: avalanche.h:69
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
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:215
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:381
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:130
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:38
Definition: net.h:856
bool ForNode(NodeId id, std::function< bool(CNode *pnode)> func)
Definition: net.cpp:3403
size_t GetNodeCount(ConnectionDirection) const
Definition: net.cpp:3102
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
Definition: net.cpp:3357
Inv(ventory) message data.
Definition: protocol.h:581
bool IsMsgBlk() const
Definition: protocol.h:612
bool IsMsgTx() const
Definition: protocol.h:600
bool IsMsgStakeContender() const
Definition: protocol.h:608
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:97
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:460
NodeId GetId() const
Definition: net.h:724
uint64_t GetLocalNonce() const
Definition: net.h:726
int GetCommonVersion() const
Definition: net.h:750
uint64_t nRemoteHostNonce
Definition: net.h:512
uint64_t nRemoteExtraEntropy
Definition: net.h:514
uint64_t GetLocalExtraEntropy() const
Definition: net.h:727
void invsPolled(uint32_t count)
The node was polled for count invs.
Definition: net.cpp:3285
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:214
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:310
CTransactionRef get(const TxId &txid) const
Definition: txmempool.cpp:573
auto withConflicting(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_conflicting)
Definition: txmempool.h:586
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1147
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1397
const Consensus::Params & GetConsensus() const
Definition: validation.h:1237
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1280
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
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 DelegationId & getId() const
Definition: delegation.h:60
const CPubKey & getDelegatedPubkey() const
Definition: delegation.cpp:60
const LimitedProofId & getLimitedProofId() const
Definition: delegation.h:61
void transactionAddedToMempool(const CTransactionRef &tx, uint64_t mempool_sequence) override
Definition: processor.cpp:139
void sendResponse(CNode *pfrom, Response response) const
Definition: processor.cpp:533
const uint32_t staleVoteThreshold
Voting parameters.
Definition: processor.h:230
void promoteStakeContendersToTip() EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards
Promote stake contender cache entries to the latest chain tip.
Definition: processor.cpp:1085
std::atomic< bool > quorumIsEstablished
Definition: processor.h:224
AnyVoteItem getVoteItemFromInv(const CInv &inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
Definition: processor.cpp:1341
Mutex cs_finalizedItems
Rolling bloom filter to track recently finalized inventory items of any type.
Definition: processor.h:450
bool sendHelloInternal(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(cs_delayedAvahelloNodeIds)
Definition: processor.cpp:698
int getConfidence(const AnyVoteItem &item) const
Definition: processor.cpp:477
bool addToReconcile(const AnyVoteItem &item) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:426
std::vector< CInv > getInvsForNextPoll(bool forPoll=true) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:1292
RWCollection< QuerySet > queries
Definition: processor.h:209
bool hasFinalizedTip() const EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizationTip)
Whether there is a finalized tip.
Definition: processor.h:333
bool setContenderStatusForLocalWinners(const CBlockIndex *pindex, std::vector< StakeContenderId > &pollableContenders) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Helper to set the vote status for local winners in the contender cache.
Definition: processor.cpp:1110
bool registerVotes(NodeId nodeid, const Response &response, std::vector< VoteItemUpdate > &updates, int &banscore, std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:540
void transactionAddedToMempool(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:1179
bool sendHello(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Send a avahello message.
Definition: processor.cpp:733
bool isRecentlyFinalized(const uint256 &itemId) const EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:491
void setRecentlyFinalized(const uint256 &itemId) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:495
bool startEventLoop(CScheduler &scheduler)
Definition: processor.cpp:765
bool isQuorumEstablished() LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:795
std::atomic< uint64_t > round
Keep track of peers and queries sent.
Definition: processor.h:173
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:222
EventLoop eventLoop
Event loop machinery.
Definition: processor.h:217
CTxMemPool * mempool
Definition: processor.h:163
int64_t minAvaproofsNodeCount
Definition: processor.h:226
const bool m_preConsensus
Definition: processor.h:268
Mutex cs_delayedAvahelloNodeIds
Definition: processor.h:240
bool setStakingRewardWinners(const CBlockIndex *pprev, const std::vector< CScript > &payouts) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards
Definition: processor.cpp:986
void runEventLoop() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:1185
Mutex cs_invalidatedBlocks
We don't need many blocks but a low false positive rate.
Definition: processor.h:437
void updatedBlockTip() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:1127
RWCollection< VoteMap > voteRecords
Items to run avalanche on.
Definition: processor.h:168
std::unique_ptr< interfaces::Handler > chainNotificationsHandler
Definition: processor.h:235
uint32_t minQuorumScore
Quorum management.
Definition: processor.h:222
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:1022
bool getStakingRewardWinners(const BlockHash &prevBlockHash, std::vector< std::pair< ProofId, CScript > > &winners) const EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards)
Definition: processor.cpp:957
std::atomic< bool > m_canShareLocalProof
Definition: processor.h:225
void cleanupStakingRewards(const int minHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards
Definition: processor.cpp:938
bool isAccepted(const AnyVoteItem &item) const
Definition: processor.cpp:463
ProofRef getLocalProof() const
Definition: processor.cpp:755
void acceptStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
Definition: processor.cpp:1053
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:444
int getStakeContenderStatus(const StakeContenderId &contenderId) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Track votes on stake contenders.
Definition: processor.cpp:1030
const uint32_t staleVoteFactor
Definition: processor.h:231
void sendDelayedAvahello() EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Definition: processor.cpp:738
void finalizeStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:1058
std::unique_ptr< PeerData > peerData
Definition: processor.h:213
bool eraseStakingRewardWinner(const BlockHash &prevBlockHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards)
Definition: processor.cpp:933
const bool m_stakingPreConsensus
Definition: processor.h:269
CConnman * connman
Definition: processor.h:161
bool isWorthPolling(const AnyVoteItem &item) const EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:1434
CPubKey getSessionPubKey() const
Definition: processor.cpp:694
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, bool stakingPreConsensus)
Definition: processor.cpp:145
ChainstateManager & chainman
Definition: processor.h:162
std::atomic< int64_t > avaproofsNodeCounter
Definition: processor.h:227
bool computeStakingReward(const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Definition: processor.cpp:888
ProofRegistrationState getLocalProofRegistrationState() const
Definition: processor.cpp:759
void clearTimedoutRequests() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
Definition: processor.cpp:1253
Mutex cs_peerManager
Keep track of the peers and associated infos.
Definition: processor.h:178
bool getLocalAcceptance(const AnyVoteItem &item) const
Definition: processor.h:483
void rejectStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
Definition: processor.cpp:1080
void avaproofsSent(NodeId nodeid) LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
Definition: processor.cpp:774
double minQuorumConnectedScoreRatio
Definition: processor.h:223
void clearFinalizedItems() EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
Definition: processor.cpp:499
static bool FromHex(Proof &proof, const std::string &hexProof, bilingual_str &errorOut)
Definition: proof.cpp:52
bool verify(const Amount &stakeUtxoDustThreshold, ProofValidationState &state) const
Definition: proof.cpp:120
static uint32_t amountToScore(Amount amount)
Definition: proof.cpp:101
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:248
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:130
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:263
#define LogPrint(category,...)
Definition: logging.h:238
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:41
std::variant< const ProofRef, const CBlockIndex *, const StakeContenderId, const CTransactionRef > AnyVoteItem
Definition: processor.h:95
static bool VerifyDelegation(const Delegation &dg, const CPubKey &expectedPubKey, bilingual_str &error)
Definition: processor.cpp:92
static bool isNull(const AnyVoteItem &item)
Definition: processor.cpp:415
static const uint256 GetVoteItemId(const AnyVoteItem &item)
Definition: processor.cpp:39
static bool VerifyProof(const Amount &stakeUtxoDustThreshold, const Proof &proof, bilingual_str &error)
Definition: processor.cpp:60
RCUPtr< const Proof > ProofRef
Definition: proof.h:186
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
Definition: init.h:31
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:259
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:36
Response response
Definition: processor.cpp:510
static constexpr std::chrono::milliseconds AVALANCHE_TIME_STEP
Run the avalanche event loop every 10ms.
Definition: processor.cpp:34
SchnorrSig sig
Definition: processor.cpp:511
static constexpr size_t AVALANCHE_CONTENDER_MAX_POLLABLE
Maximum number of stake contenders to poll for, leaving room for polling blocks and proofs in the sam...
Definition: processor.h:60
static constexpr std::chrono::milliseconds AVALANCHE_DEFAULT_QUERY_TIMEOUT
How long before we consider that a query timed out.
Definition: processor.h:65
static constexpr size_t AVALANCHE_MAX_ELEMENT_POLL
Maximum item that can be polled at once.
Definition: processor.h:54
static constexpr int AVALANCHE_MAX_PROOF_STAKES
How many UTXOs can be used for a single proof.
Definition: proof.h:30
@ MSG_TX
Definition: protocol.h:565
@ MSG_AVA_STAKE_CONTENDER
Definition: protocol.h:573
@ 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)
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:1439
bool operator()(const CBlockIndex *pindex) const LOCKS_EXCLUDED(cs_main)
Definition: processor.cpp:1372
ProofRegistrationState proofState GUARDED_BY(cs_proofState)
std::vector< std::pair< ProofId, CScript > > winners
Definition: processor.h:251
StakeContenderIds are unique for each block to ensure that the peer polling for their acceptance has ...
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
bool ParseFixedPoint(std::string_view val, int decimals, int64_t *amount_out)
Parse number as fixed point according to JSON number syntax.
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