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