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