Changeset View
Changeset View
Standalone View
Standalone View
src/avalanche/proofpool.cpp
// Copyright (c) 2021 The Bitcoin developers | // Copyright (c) 2021 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <avalanche/proofpool.h> | #include <avalanche/proofpool.h> | ||||
#include <avalanche/peermanager.h> | #include <avalanche/peermanager.h> | ||||
#include <avalanche/proofcomparator.h> | |||||
namespace avalanche { | namespace avalanche { | ||||
ProofPool::AddProofStatus ProofPool::addProof(const ProofRef &proof) { | ProofPool::AddProofStatus | ||||
assert(proof); | ProofPool::addProofIfNoConflict(const ProofRef &proof) { | ||||
ConflictingProofSet dummy; | |||||
return addProofIfNoConflict(proof, dummy); | |||||
} | |||||
deadalnix: You should put this kind of dummy functions in the header. | |||||
ProofPool::AddProofStatus | |||||
ProofPool::addProofIfNoConflict(const ProofRef &proof, | |||||
ConflictingProofSet &conflictingProofs) { | |||||
const ProofId &proofid = proof->getId(); | const ProofId &proofid = proof->getId(); | ||||
auto &poolView = pool.get<by_proofid>(); | auto &poolView = pool.get<by_proofid>(); | ||||
if (poolView.find(proofid) != poolView.end()) { | if (poolView.find(proofid) != poolView.end()) { | ||||
return AddProofStatus::DUPLICATED; | return AddProofStatus::DUPLICATED; | ||||
} | } | ||||
// Attach UTXOs to this proof. | // Attach UTXOs to this proof. | ||||
std::unordered_set<ProofRef> conflicting_proofs; | |||||
for (size_t i = 0; i < proof->getStakes().size(); i++) { | for (size_t i = 0; i < proof->getStakes().size(); i++) { | ||||
auto p = pool.emplace(i, proof); | auto p = pool.emplace(i, proof); | ||||
if (!p.second) { | if (!p.second) { | ||||
// We have a collision with an existing proof. | // We have a collision with an existing proof. | ||||
conflicting_proofs.insert(p.first->proof); | conflictingProofs.insert(p.first->proof); | ||||
} | } | ||||
} | } | ||||
// For now, if there is a conflict, just cleanup the mess. | // If there is a conflict, just cleanup the mess. | ||||
if (conflicting_proofs.size() > 0) { | if (conflictingProofs.size() > 0) { | ||||
deadalnixUnsubmitted Not Done Inline ActionsYou don't know if the set was empty to begin with, so this is not a valid check anymore. You probably need ot add check with set that are non empty to make sure the behavior is what you expect. deadalnix: You don't know if the set was empty to begin with, so this is not a valid check anymore.
You… | |||||
FabienAuthorUnsubmitted Done Inline ActionsGood catch Fabien: Good catch | |||||
for (const auto &s : proof->getStakes()) { | for (const auto &s : proof->getStakes()) { | ||||
auto it = pool.find(s.getStake().getUTXO()); | auto it = pool.find(s.getStake().getUTXO()); | ||||
assert(it != pool.end()); | assert(it != pool.end()); | ||||
// We need to delete that one. | // We need to delete that one. | ||||
if (it->proof->getId() == proofid) { | if (it->proof->getId() == proofid) { | ||||
pool.erase(it); | pool.erase(it); | ||||
} | } | ||||
} | } | ||||
return AddProofStatus::REJECTED; | return AddProofStatus::REJECTED; | ||||
} | } | ||||
return AddProofStatus::SUCCEED; | return AddProofStatus::SUCCEED; | ||||
} | } | ||||
ProofPool::AddProofStatus | |||||
ProofPool::addProofIfPreferred(const ProofRef &proof) { | |||||
ConflictingProofSet dummy; | |||||
return addProofIfPreferred(proof, dummy); | |||||
} | |||||
deadalnixUnsubmitted Not Done Inline ActionsThis should be moved to the header too. deadalnix: This should be moved to the header too. | |||||
ProofPool::AddProofStatus | |||||
ProofPool::addProofIfPreferred(const ProofRef &proof, | |||||
ConflictingProofSet &conflictingProofs) { | |||||
auto added = addProofIfNoConflict(proof, conflictingProofs); | |||||
ConflictingProofComparator compare; | |||||
// In case the proof was rejected due to conflict and it is the best | |||||
// candidate, override the conflicting ones and add it again | |||||
if (!added && compare(proof, *conflictingProofs.begin())) { | |||||
deadalnixUnsubmitted Not Done Inline ActionsOnce again, this check is not valid if the set wasn't empty to begin with. deadalnix: Once again, this check is not valid if the set wasn't empty to begin with. | |||||
for (auto &conflictingProof : conflictingProofs) { | |||||
removeProof(conflictingProof); | |||||
} | |||||
added = addProofIfNoConflict(proof); | |||||
assert(added == AddProofStatus::SUCCEED); | |||||
} | |||||
return added; | |||||
} | |||||
// Having the ProofRef passed by reference is risky because the proof could be | // Having the ProofRef passed by reference is risky because the proof could be | ||||
// deleted during the erasure loop, so we pass it by value. Since it's a shared | // deleted during the erasure loop, so we pass it by value. Since it's a shared | ||||
// pointer, the copy is cheap enough and should not have any significant impact | // pointer, the copy is cheap enough and should not have any significant impact | ||||
// on performance. | // on performance. | ||||
bool ProofPool::removeProof(ProofRef proof) { | bool ProofPool::removeProof(ProofRef proof) { | ||||
auto &poolView = pool.get<by_proofid>(); | auto &poolView = pool.get<by_proofid>(); | ||||
return poolView.erase(proof->getId()); | return poolView.erase(proof->getId()); | ||||
} | } | ||||
Show All 22 Lines |
You should put this kind of dummy functions in the header.