diff --git a/src/avalanche/peermanager.h b/src/avalanche/peermanager.h --- a/src/avalanche/peermanager.h +++ b/src/avalanche/peermanager.h @@ -9,6 +9,7 @@ #include <avalanche/proof.h> #include <avalanche/proofpool.h> #include <avalanche/proofradixtreeadapter.h> +#include <avalanche/stakecontendercache.h> #include <coins.h> #include <common/bloom.h> #include <consensus/validation.h> @@ -294,6 +295,8 @@ std::unordered_set<ProofId, SaltedProofIdHasher> manualFlakyProofids; + StakeContenderCache stakeContenderCache; + public: static constexpr size_t MAX_REMOTE_PROOFS{100}; @@ -452,6 +455,24 @@ } } + /** Make some of the contender cache API available */ + void cleanupStakeContenders(const int requestedMinHeight); + void addStakeContender(const ProofRef &proof); + int getStakeContenderStatus(const StakeContenderId &contenderId, + BlockHash &prevblockhashout) const; + void acceptStakeContender(const StakeContenderId &contenderId); + void finalizeStakeContender(const StakeContenderId &contenderId); + void rejectStakeContender(const StakeContenderId &contenderId); + void promoteStakeContendersToBlock(const CBlockIndex *pindex); + bool setStakeContenderWinners(const CBlockIndex *pindex, + const std::vector<CScript> &payoutScripts); + size_t getPollableContenders( + const BlockHash &prevblockhash, size_t maxPollable, + std::vector<StakeContenderId> &pollableContenders) const; + bool getStakeContenderWinners( + const BlockHash &prevblockhash, + std::vector<std::pair<ProofId, CScript>> &winners) const; + /**************************************************** * Functions which are public for testing purposes. * ****************************************************/ diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp --- a/src/avalanche/peermanager.cpp +++ b/src/avalanche/peermanager.cpp @@ -1390,4 +1390,52 @@ return true; } +void PeerManager::cleanupStakeContenders(const int requestedMinHeight) { + stakeContenderCache.cleanup(requestedMinHeight); +} + +void PeerManager::addStakeContender(const ProofRef &proof) { + const CBlockIndex *tip = WITH_LOCK(cs_main, return chainman.ActiveTip()); + stakeContenderCache.add(tip, proof); +} + +int PeerManager::getStakeContenderStatus(const StakeContenderId &contenderId, + BlockHash &prevblockhashout) const { + return stakeContenderCache.getVoteStatus(contenderId, prevblockhashout); +} + +void PeerManager::acceptStakeContender(const StakeContenderId &contenderId) { + stakeContenderCache.accept(contenderId); +} + +void PeerManager::finalizeStakeContender(const StakeContenderId &contenderId) { + stakeContenderCache.finalize(contenderId); +} + +void PeerManager::rejectStakeContender(const StakeContenderId &contenderId) { + stakeContenderCache.reject(contenderId); +} + +void PeerManager::promoteStakeContendersToBlock(const CBlockIndex *pindex) { + stakeContenderCache.promoteToBlock(pindex, *this); +} + +bool PeerManager::setStakeContenderWinners( + const CBlockIndex *pindex, const std::vector<CScript> &payoutScripts) { + return stakeContenderCache.setWinners(pindex, payoutScripts); +} + +size_t PeerManager::getPollableContenders( + const BlockHash &prevblockhash, size_t maxPollable, + std::vector<StakeContenderId> &pollableContenders) const { + return stakeContenderCache.getPollableContenders(prevblockhash, maxPollable, + pollableContenders); +} + +bool PeerManager::getStakeContenderWinners( + const BlockHash &prevblockhash, + std::vector<std::pair<ProofId, CScript>> &winners) const { + return stakeContenderCache.getWinners(prevblockhash, winners); +} + } // namespace avalanche diff --git a/src/avalanche/processor.h b/src/avalanche/processor.h --- a/src/avalanche/processor.h +++ b/src/avalanche/processor.h @@ -11,7 +11,6 @@ #include <avalanche/proofcomparator.h> #include <avalanche/protocol.h> #include <avalanche/stakecontender.h> -#include <avalanche/stakecontendercache.h> #include <avalanche/voterecord.h> // For AVALANCHE_MAX_INFLIGHT_POLL #include <blockindex.h> #include <blockindexcomparators.h> @@ -255,9 +254,6 @@ std::unordered_map<BlockHash, StakingReward, SaltedUint256Hasher> stakingRewards GUARDED_BY(cs_stakingRewards); - mutable Mutex cs_stakeContenderCache; - StakeContenderCache stakeContenderCache GUARDED_BY(cs_stakeContenderCache); - Processor(Config avaconfig, interfaces::Chain &chain, CConnman *connmanIn, ChainstateManager &chainman, CTxMemPool *mempoolIn, CScheduler &scheduler, std::unique_ptr<PeerData> peerDataIn, @@ -348,16 +344,16 @@ } bool isQuorumEstablished() LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager, !cs_stakingRewards, - !cs_stakeContenderCache, !cs_finalizedItems); + !cs_finalizedItems); bool canShareLocalProof(); bool computeStakingReward(const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager, !cs_stakingRewards, - !cs_stakeContenderCache, !cs_finalizedItems); + !cs_finalizedItems); bool eraseStakingRewardWinner(const BlockHash &prevBlockHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards); void cleanupStakingRewards(const int minHeight) - EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards, !cs_stakeContenderCache); + EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards, !cs_peerManager); bool getStakingRewardWinners( const BlockHash &prevBlockHash, std::vector<std::pair<ProofId, CScript>> &winners) const @@ -367,7 +363,7 @@ EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards); bool setStakingRewardWinners(const CBlockIndex *pprev, const std::vector<CScript> &payouts) - EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards, !cs_stakeContenderCache); + EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards, !cs_peerManager); bool setStakingRewardWinners( const CBlockIndex *pprev, const std::vector<std::pair<ProofId, CScript>> &winners) @@ -391,33 +387,30 @@ /** Track votes on stake contenders */ void addStakeContender(const ProofRef &proof) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, !cs_stakeContenderCache); + EXCLUSIVE_LOCKS_REQUIRED(!cs_main, !cs_peerManager); int getStakeContenderStatus(const StakeContenderId &contenderId) const - EXCLUSIVE_LOCKS_REQUIRED(!cs_stakeContenderCache, !cs_stakingRewards); + EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager, !cs_stakingRewards); void acceptStakeContender(const StakeContenderId &contenderId) - EXCLUSIVE_LOCKS_REQUIRED(!cs_stakeContenderCache); + EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager); void finalizeStakeContender(const StakeContenderId &contenderId) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, !cs_stakeContenderCache, - !cs_stakingRewards); + EXCLUSIVE_LOCKS_REQUIRED(!cs_main, !cs_peerManager, !cs_stakingRewards); void rejectStakeContender(const StakeContenderId &contenderId) - EXCLUSIVE_LOCKS_REQUIRED(!cs_stakeContenderCache); + EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager); /** Promote stake contender cache entries to the latest chain tip */ void promoteStakeContendersToTip() - EXCLUSIVE_LOCKS_REQUIRED(!cs_stakeContenderCache, !cs_stakingRewards, - !cs_peerManager, !cs_finalizationTip, - !cs_finalizedItems); + EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards, !cs_peerManager, + !cs_finalizationTip, !cs_finalizedItems); private: void updatedBlockTip() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager, !cs_finalizedItems, - !cs_finalizationTip, !cs_stakeContenderCache, - !cs_stakingRewards); + !cs_finalizationTip, !cs_stakingRewards); void transactionAddedToMempool(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems); void runEventLoop() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager, !cs_stakingRewards, - !cs_stakeContenderCache, !cs_finalizedItems); + !cs_finalizedItems); void clearTimedoutRequests() EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager); std::vector<CInv> getInvsForNextPoll(bool forPoll = true) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager, !cs_finalizedItems); @@ -434,7 +427,7 @@ bool setContenderStatusForLocalWinners( const CBlockIndex *pindex, std::vector<StakeContenderId> &pollableContenders) - EXCLUSIVE_LOCKS_REQUIRED(!cs_stakeContenderCache, !cs_stakingRewards); + EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager, !cs_stakingRewards); /** * We don't need many blocks but a low false positive rate. @@ -469,7 +462,7 @@ bool operator()(const ProofRef &proof) const LOCKS_EXCLUDED(cs_peerManager); bool operator()(const StakeContenderId &contenderId) const - LOCKS_EXCLUDED(cs_stakeContenderCache, cs_stakingRewards); + LOCKS_EXCLUDED(cs_peerManager, cs_stakingRewards); bool operator()(const CTransactionRef &tx) const; }; bool isWorthPolling(const AnyVoteItem &item) const diff --git a/src/avalanche/processor.cpp b/src/avalanche/processor.cpp --- a/src/avalanche/processor.cpp +++ b/src/avalanche/processor.cpp @@ -956,8 +956,8 @@ } if (m_stakingPreConsensus) { - WITH_LOCK(cs_stakeContenderCache, - return stakeContenderCache.cleanup(minHeight)); + WITH_LOCK(cs_peerManager, + return peerManager->cleanupStakeContenders(minHeight)); } } @@ -1003,8 +1003,8 @@ } if (m_stakingPreConsensus) { - LOCK(cs_stakeContenderCache); - stakeContenderCache.setWinners(pprev, payouts); + LOCK(cs_peerManager); + peerManager->setStakeContenderWinners(pprev, payouts); } LOCK(cs_stakingRewards); @@ -1035,21 +1035,18 @@ } void Processor::addStakeContender(const ProofRef &proof) { - AssertLockHeld(cs_main); - const CBlockIndex *activeTip = chainman.ActiveTip(); - WITH_LOCK(cs_stakeContenderCache, - return stakeContenderCache.add(activeTip, proof)); + WITH_LOCK(cs_peerManager, return peerManager->addStakeContender(proof)); } int Processor::getStakeContenderStatus( const StakeContenderId &contenderId) const { - AssertLockNotHeld(cs_stakeContenderCache); + AssertLockNotHeld(cs_peerManager); AssertLockNotHeld(cs_stakingRewards); BlockHash prevblockhash; - int status = WITH_LOCK( - cs_stakeContenderCache, - return stakeContenderCache.getVoteStatus(contenderId, prevblockhash)); + int status = + WITH_LOCK(cs_peerManager, return peerManager->getStakeContenderStatus( + contenderId, prevblockhash)); if (status != -1) { std::vector<std::pair<ProofId, CScript>> winners; @@ -1065,27 +1062,26 @@ } void Processor::acceptStakeContender(const StakeContenderId &contenderId) { - LOCK(cs_stakeContenderCache); - stakeContenderCache.accept(contenderId); + LOCK(cs_peerManager); + peerManager->acceptStakeContender(contenderId); } void Processor::finalizeStakeContender(const StakeContenderId &contenderId) { - AssertLockHeld(cs_main); - const CBlockIndex *tip; std::vector<std::pair<ProofId, CScript>> winners; { - LOCK(cs_stakeContenderCache); - stakeContenderCache.finalize(contenderId); + LOCK(cs_peerManager); + peerManager->finalizeStakeContender(contenderId); // Get block hash related to this contender. We should not assume the // current chain tip is the block this contender is a winner for. BlockHash prevblockhash; - stakeContenderCache.getVoteStatus(contenderId, prevblockhash); + peerManager->getStakeContenderStatus(contenderId, prevblockhash); - tip = chainman.m_blockman.LookupBlockIndex(prevblockhash); + tip = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex( + prevblockhash)); - stakeContenderCache.getWinners(tip->GetBlockHash(), winners); + peerManager->getStakeContenderWinners(tip->GetBlockHash(), winners); } // Set staking rewards to include newly finalized contender @@ -1095,8 +1091,8 @@ } void Processor::rejectStakeContender(const StakeContenderId &contenderId) { - LOCK(cs_stakeContenderCache); - stakeContenderCache.reject(contenderId); + LOCK(cs_peerManager); + peerManager->rejectStakeContender(contenderId); } void Processor::promoteStakeContendersToTip() { @@ -1111,8 +1107,7 @@ { LOCK(cs_peerManager); - LOCK(cs_stakeContenderCache); - stakeContenderCache.promoteToBlock(activeTip, *peerManager); + peerManager->promoteStakeContendersToBlock(activeTip); } // If staking rewards have not been computed yet, we will try again when @@ -1137,21 +1132,21 @@ } // Set status for local winners - LOCK(cs_stakeContenderCache); + LOCK(cs_peerManager); for (const auto &winner : winners) { const StakeContenderId contenderId(prevblockhash, winner.first); - stakeContenderCache.finalize(contenderId); + peerManager->finalizeStakeContender(contenderId); } // Treat the highest ranking contender similarly to local winners except // that it is not automatically included in the winner set (unless it // happens to be selected as a local winner). - if (stakeContenderCache.getPollableContenders( - prevblockhash, AVALANCHE_CONTENDER_MAX_POLLABLE, - pollableContenders) > 0) { + if (peerManager->getPollableContenders(prevblockhash, + AVALANCHE_CONTENDER_MAX_POLLABLE, + pollableContenders) > 0) { // Accept the highest ranking contender. This is a no-op if the highest // ranking contender is already the local winner. - stakeContenderCache.accept(pollableContenders[0]); + peerManager->acceptStakeContender(pollableContenders[0]); return true; } @@ -1448,7 +1443,7 @@ bool Processor::IsWorthPolling::operator()( const StakeContenderId &contenderId) const { - AssertLockNotHeld(processor.cs_stakeContenderCache); + AssertLockNotHeld(processor.cs_peerManager); AssertLockNotHeld(processor.cs_stakingRewards); // Only worth polling for contenders that we know about @@ -1493,7 +1488,7 @@ bool Processor::GetLocalAcceptance::operator()( const StakeContenderId &contenderId) const { - AssertLockNotHeld(processor.cs_stakeContenderCache); + AssertLockNotHeld(processor.cs_peerManager); AssertLockNotHeld(processor.cs_stakingRewards); return processor.getStakeContenderStatus(contenderId) == 0; diff --git a/src/avalanche/test/processor_tests.cpp b/src/avalanche/test/processor_tests.cpp --- a/src/avalanche/test/processor_tests.cpp +++ b/src/avalanche/test/processor_tests.cpp @@ -409,16 +409,13 @@ const StakeContenderId contenderId(chaintip->GetBlockHash(), proof->getId()); - { - LOCK(cs_main); - fixture->m_processor->addStakeContender(proof); + fixture->m_processor->addStakeContender(proof); - // Many of these tests assume that building a new item means it is - // accepted by default. Contenders are different in that they are - // only accepted if they are a stake winner. We stick the the - // convention for these tests and accept the contender. - fixture->m_processor->acceptStakeContender(contenderId); - } + // Many of these tests assume that building a new item means it is + // accepted by default. Contenders are different in that they are + // only accepted if they are a stake winner. We stick the the + // convention for these tests and accept the contender. + fixture->m_processor->acceptStakeContender(contenderId); BOOST_CHECK( fixture->m_processor->getStakeContenderStatus(contenderId) == 0); @@ -2574,11 +2571,8 @@ // Add stake contenders. Without computing staking rewards, the status is // pending. - { - LOCK(cs_main); - m_processor->addStakeContender(proof1); - m_processor->addStakeContender(proof2); - } + m_processor->addStakeContender(proof1); + m_processor->addStakeContender(proof2); BOOST_CHECK_EQUAL(m_processor->getStakeContenderStatus(contender1_block1), -2); BOOST_CHECK_EQUAL(m_processor->getStakeContenderStatus(contender2_block1), @@ -2731,7 +2725,7 @@ }); // Add it as a stake contender so it will be promoted - WITH_LOCK(cs_main, m_processor->addStakeContender(proof)); + m_processor->addStakeContender(proof); proofs.emplace_back(std::move(proof)); } @@ -2792,7 +2786,7 @@ ->m_blockman.LookupBlockIndex(block.GetHash())); auto bestproof = buildRandomProof(active_chainstate, std::numeric_limits<uint32_t>::max()); - WITH_LOCK(cs_main, m_processor->addStakeContender(bestproof)); + m_processor->addStakeContender(bestproof); AvalancheTest::updatedBlockTip(*m_processor); // Compute local stake winners @@ -2827,10 +2821,7 @@ ProofId localWinnerProofId = localWinnerProof->getId(); const StakeContenderId localWinnerContenderId(chaintipHash, localWinnerProof->getId()); - { - LOCK(cs_main); - m_processor->addStakeContender(localWinnerProof); - } + m_processor->addStakeContender(localWinnerProof); // Prepare the proof so that it becomes the local stake winner m_processor->withPeerManager([&](avalanche::PeerManager &pm) { @@ -2865,10 +2856,7 @@ numContenders < AVALANCHE_CONTENDER_MAX_POLLABLE * 10; numContenders++) { auto proof = buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE); - { - LOCK(cs_main); - m_processor->addStakeContender(proof); - } + m_processor->addStakeContender(proof); const StakeContenderId contenderId(chaintipHash, proof->getId()); double rank = contenderId.ComputeProofRewardRank(MIN_VALID_PROOF_SCORE); diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -6956,7 +6956,6 @@ break; } case avalanche::VoteStatus::Finalized: { - LOCK(cs_main); m_avalanche->finalizeStakeContender(contenderId); break; } @@ -9217,7 +9216,7 @@ saveProofIfStaker(node, proofid, nodeid); if (isStaker && m_opts.avalanche_staking_preconsensus) { - WITH_LOCK(cs_main, m_avalanche->addStakeContender(proof)); + m_avalanche->addStakeContender(proof); } return true;