Changeset View
Changeset View
Standalone View
Standalone View
src/avalanche/processor.cpp
| Show First 20 Lines • Show All 308 Lines • ▼ Show 20 Lines | std::unique_ptr<Processor> Processor::MakeProcessor(const ArgsManager &argsman, | ||||
| // We can't use std::make_unique with a private constructor | // We can't use std::make_unique with a private constructor | ||||
| return std::unique_ptr<Processor>(new Processor( | return std::unique_ptr<Processor>(new Processor( | ||||
| argsman, chain, connman, std::move(peerData), std::move(sessionKey), | argsman, chain, connman, std::move(peerData), std::move(sessionKey), | ||||
| Proof::amountToScore(minQuorumStake), minQuorumConnectedStakeRatio, | Proof::amountToScore(minQuorumStake), minQuorumConnectedStakeRatio, | ||||
| minAvaproofsNodeCount, staleVoteThreshold, staleVoteFactor)); | minAvaproofsNodeCount, staleVoteThreshold, staleVoteFactor)); | ||||
| } | } | ||||
| bool Processor::addBlockToReconcile(const CBlockIndex *pindex) { | bool Processor::addBlockToReconcile(const CBlockIndex *pindex) { | ||||
| bool isAccepted; | |||||
| if (!pindex) { | if (!pindex) { | ||||
| // isWorthPolling expects this to be non-null, so bail early. | // isWorthPolling expects this to be non-null, so bail early. | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool isAccepted; | |||||
| { | { | ||||
| LOCK(cs_main); | LOCK(cs_main); | ||||
| if (!isWorthPolling(pindex)) { | if (!isWorthPolling(pindex)) { | ||||
| // There is no point polling this block. | // There is no point polling this block. | ||||
| return false; | return false; | ||||
| } | } | ||||
| isAccepted = ::ChainActive().Contains(pindex); | isAccepted = ::ChainActive().Contains(pindex); | ||||
| } | } | ||||
| return blockVoteRecords.getWriteView() | return blockVoteRecords.getWriteView() | ||||
| ->insert(std::make_pair(pindex, VoteRecord(isAccepted))) | ->insert(std::make_pair(pindex, VoteRecord(isAccepted))) | ||||
| .second; | .second; | ||||
| } | } | ||||
| void Processor::addProofToReconcile(const ProofRef &proof) { | bool Processor::addProofToReconcile(const ProofRef &proof) { | ||||
| // TODO We don't want to accept an infinite number of conflicting proofs. | if (!proof) { | ||||
| // They should be some rules to make them expensive and/or limited by | // isWorthPolling expects this to be non-null, so bail early. | ||||
| // design. | return false; | ||||
| const bool isAccepted = WITH_LOCK( | } | ||||
| cs_peerManager, return peerManager->isBoundToPeer(proof->getId())); | |||||
| bool isAccepted; | |||||
| { | |||||
| LOCK(cs_peerManager); | |||||
| if (!isWorthPolling(proof)) { | |||||
| return false; | |||||
| } | |||||
| isAccepted = peerManager->isBoundToPeer(proof->getId()); | |||||
| } | |||||
| proofVoteRecords.getWriteView()->insert( | return proofVoteRecords.getWriteView() | ||||
| std::make_pair(proof, VoteRecord(isAccepted))); | ->insert(std::make_pair(proof, VoteRecord(isAccepted))) | ||||
| .second; | |||||
| } | } | ||||
| bool Processor::isAccepted(const CBlockIndex *pindex) const { | bool Processor::isAccepted(const CBlockIndex *pindex) const { | ||||
| if (!pindex) { | if (!pindex) { | ||||
| // CBlockIndexWorkComparator expects this to be non-null, so bail early. | // CBlockIndexWorkComparator expects this to be non-null, so bail early. | ||||
| return false; | return false; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < size; i++) { | ||||
| } | } | ||||
| responseIndex.insert(std::make_pair(pindex, votes[i])); | responseIndex.insert(std::make_pair(pindex, votes[i])); | ||||
| } | } | ||||
| if (invs[i].IsMsgProof()) { | if (invs[i].IsMsgProof()) { | ||||
| const ProofId proofid(votes[i].GetHash()); | const ProofId proofid(votes[i].GetHash()); | ||||
| const ProofRef proof = WITH_LOCK( | ProofRef proof; | ||||
| cs_peerManager, return peerManager->getProof(proofid)); | { | ||||
| LOCK(cs_peerManager); | |||||
| proof = peerManager->getProof(proofid); | |||||
| if (!proof) { | if (!proof) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (!isWorthPolling(proof)) { | |||||
| continue; | |||||
| } | |||||
| } | |||||
| responseProof.insert(std::make_pair(proof, votes[i])); | responseProof.insert(std::make_pair(proof, votes[i])); | ||||
| } | } | ||||
| } | } | ||||
| // Thanks to C++14 generic lambdas, we can apply the same logic to various | // Thanks to C++14 generic lambdas, we can apply the same logic to various | ||||
| // parameter types sharing the same interface. | // parameter types sharing the same interface. | ||||
| auto registerVoteItems = [&](auto voteRecordsWriteView, auto &updates, | auto registerVoteItems = [&](auto voteRecordsWriteView, auto &updates, | ||||
| auto responseItems) { | auto responseItems) { | ||||
| ▲ Show 20 Lines • Show All 292 Lines • ▼ Show 20 Lines | for (const auto &p : timedout_items) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| std::vector<CInv> Processor::getInvsForNextPoll(bool forPoll) { | std::vector<CInv> Processor::getInvsForNextPoll(bool forPoll) { | ||||
| std::vector<CInv> invs; | std::vector<CInv> invs; | ||||
| // Use NO_THREAD_SAFETY_ANALYSIS to avoid false positive due to | |||||
| // isWorthPolling requiring a different lock depending of the prototype. | |||||
| auto removeItemsNotWorthPolling = | |||||
| [&](auto &itemVoteRecords) NO_THREAD_SAFETY_ANALYSIS { | |||||
| auto w = itemVoteRecords.getWriteView(); | |||||
| for (auto it = w->begin(); it != w->end();) { | |||||
| if (!isWorthPolling(it->first)) { | |||||
| it = w->erase(it); | |||||
| } else { | |||||
| ++it; | |||||
| } | |||||
| } | |||||
| }; | |||||
| auto extractVoteRecordsToInvs = [&](const auto &itemVoteRecordRange, | auto extractVoteRecordsToInvs = [&](const auto &itemVoteRecordRange, | ||||
| auto buildInvFromVoteItem) { | auto buildInvFromVoteItem) { | ||||
| for (const auto &[item, voteRecord] : itemVoteRecordRange) { | for (const auto &[item, voteRecord] : itemVoteRecordRange) { | ||||
| if (invs.size() >= AVALANCHE_MAX_ELEMENT_POLL) { | if (invs.size() >= AVALANCHE_MAX_ELEMENT_POLL) { | ||||
| // Make sure we do not produce more invs than specified by the | // Make sure we do not produce more invs than specified by the | ||||
| // protocol. | // protocol. | ||||
| return true; | return true; | ||||
| } | } | ||||
| const bool shouldPoll = | const bool shouldPoll = | ||||
| forPoll ? voteRecord.registerPoll() : voteRecord.shouldPoll(); | forPoll ? voteRecord.registerPoll() : voteRecord.shouldPoll(); | ||||
| if (!shouldPoll) { | if (!shouldPoll) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| invs.emplace_back(buildInvFromVoteItem(item)); | invs.emplace_back(buildInvFromVoteItem(item)); | ||||
| } | } | ||||
| return invs.size() >= AVALANCHE_MAX_ELEMENT_POLL; | return invs.size() >= AVALANCHE_MAX_ELEMENT_POLL; | ||||
| }; | }; | ||||
| // First remove all proofs that are not worth polling. | |||||
| WITH_LOCK(cs_peerManager, removeItemsNotWorthPolling(proofVoteRecords)); | |||||
| if (extractVoteRecordsToInvs(proofVoteRecords.getReadView(), | if (extractVoteRecordsToInvs(proofVoteRecords.getReadView(), | ||||
| [](const ProofRef &proof) { | [](const ProofRef &proof) { | ||||
| return CInv(MSG_AVA_PROOF, proof->getId()); | return CInv(MSG_AVA_PROOF, proof->getId()); | ||||
| })) { | })) { | ||||
| // The inventory vector is full, we're done | // The inventory vector is full, we're done | ||||
| return invs; | return invs; | ||||
| } | } | ||||
| // First remove all blocks that are not worth polling. | // First remove all blocks that are not worth polling. | ||||
| { | WITH_LOCK(cs_main, removeItemsNotWorthPolling(blockVoteRecords)); | ||||
| LOCK(cs_main); | |||||
| auto w = blockVoteRecords.getWriteView(); | |||||
| for (auto it = w->begin(); it != w->end();) { | |||||
| const CBlockIndex *pindex = it->first; | |||||
| if (!isWorthPolling(pindex)) { | |||||
| w->erase(it++); | |||||
| } else { | |||||
| ++it; | |||||
| } | |||||
| } | |||||
| } | |||||
| auto r = blockVoteRecords.getReadView(); | auto r = blockVoteRecords.getReadView(); | ||||
| extractVoteRecordsToInvs(reverse_iterate(r), [](const CBlockIndex *pindex) { | extractVoteRecordsToInvs(reverse_iterate(r), [](const CBlockIndex *pindex) { | ||||
| return CInv(MSG_BLOCK, pindex->GetBlockHash()); | return CInv(MSG_BLOCK, pindex->GetBlockHash()); | ||||
| }); | }); | ||||
| return invs; | return invs; | ||||
| } | } | ||||
| Show All 24 Lines | bool Processor::isWorthPolling(const CBlockIndex *pindex) const { | ||||
| if (::ChainstateActive().IsBlockFinalized(pindex)) { | if (::ChainstateActive().IsBlockFinalized(pindex)) { | ||||
| // There is no point polling finalized block. | // There is no point polling finalized block. | ||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool Processor::isWorthPolling(const ProofRef &proof) const { | |||||
| AssertLockHeld(cs_peerManager); | |||||
| const ProofId &proofid = proof->getId(); | |||||
| // No point polling orphans or discarded proofs | |||||
| return peerManager->isBoundToPeer(proofid) || | |||||
| peerManager->isInConflictingPool(proofid); | |||||
deadalnix: This just breaks everything. As soon as you invalidate a proof, you'll stop polling. the… | |||||
FabienAuthorUnsubmitted Done Inline ActionsAs per our discussion, this code considers the proof is not worth polling if:
So it's not worth polling:
Fabien: As per our discussion, this code considers the proof is not worth polling if:
- there is a… | |||||
| } | |||||
| } // namespace avalanche | } // namespace avalanche | ||||
This just breaks everything. As soon as you invalidate a proof, you'll stop polling. the network has no chance to reconciliate anything.