Changeset View
Changeset View
Standalone View
Standalone View
src/avalanche/peermanager.cpp
// Copyright (c) 2020 The Bitcoin developers | // Copyright (c) 2020 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/peermanager.h> | #include <avalanche/peermanager.h> | ||||
#include <avalanche/delegation.h> | #include <avalanche/delegation.h> | ||||
#include <avalanche/validation.h> | #include <avalanche/validation.h> | ||||
#include <random.h> | #include <random.h> | ||||
#include <validation.h> // For ChainstateActive() | #include <validation.h> // For ChainstateActive() | ||||
#include <cassert> | #include <cassert> | ||||
namespace avalanche { | namespace avalanche { | ||||
static bool isOrphanState(const ProofValidationState &state) { | |||||
return state.GetResult() == ProofValidationResult::MISSING_UTXO || | |||||
state.GetResult() == ProofValidationResult::HEIGHT_MISMATCH; | |||||
} | |||||
bool PeerManager::addNode(NodeId nodeid, const std::shared_ptr<Proof> &proof, | bool PeerManager::addNode(NodeId nodeid, const std::shared_ptr<Proof> &proof, | ||||
const Delegation &delegation) { | const Delegation &delegation) { | ||||
auto it = fetchOrCreatePeer(proof); | auto it = fetchOrCreatePeer(proof); | ||||
if (it == peers.end()) { | if (it == peers.end()) { | ||||
return false; | return false; | ||||
} | } | ||||
const PeerId peerid = it->peerid; | const PeerId peerid = it->peerid; | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | for (int retry = 0; retry < SELECT_NODE_MAX_RETRY; retry++) { | ||||
} | } | ||||
} | } | ||||
return NO_NODE; | return NO_NODE; | ||||
} | } | ||||
void PeerManager::updatedBlockTip() { | void PeerManager::updatedBlockTip() { | ||||
std::vector<PeerId> invalidPeers; | std::vector<PeerId> invalidPeers; | ||||
std::vector<std::shared_ptr<Proof>> newOrphans; | |||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | ||||
for (const auto &p : peers) { | for (const auto &p : peers) { | ||||
ProofValidationState state; | ProofValidationState state; | ||||
if (!p.proof->verify(state, coins)) { | if (!p.proof->verify(state, coins)) { | ||||
if (isOrphanState(state)) { | |||||
newOrphans.push_back(p.proof); | |||||
} | |||||
invalidPeers.push_back(p.peerid); | invalidPeers.push_back(p.peerid); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
orphanProofs.rescan(*this); | |||||
for (auto &p : newOrphans) { | |||||
orphanProofs.addProof(p); | |||||
} | |||||
for (const auto &pid : invalidPeers) { | for (const auto &pid : invalidPeers) { | ||||
removePeer(pid); | removePeer(pid); | ||||
} | } | ||||
} | } | ||||
PeerId PeerManager::getPeerId(const std::shared_ptr<Proof> &proof) { | PeerId PeerManager::getPeerId(const std::shared_ptr<Proof> &proof) { | ||||
auto it = fetchOrCreatePeer(proof); | auto it = fetchOrCreatePeer(proof); | ||||
return it == peers.end() ? NO_PEER : it->peerid; | return it == peers.end() ? NO_PEER : it->peerid; | ||||
Show All 11 Lines | PeerManager::fetchOrCreatePeer(const std::shared_ptr<Proof> &proof) { | ||||
// Check if we already know of that peer. | // Check if we already know of that peer. | ||||
auto &pview = peers.get<proof_index>(); | auto &pview = peers.get<proof_index>(); | ||||
auto it = pview.find(proof->getId()); | auto it = pview.find(proof->getId()); | ||||
if (it != pview.end()) { | if (it != pview.end()) { | ||||
return peers.project<0>(it); | return peers.project<0>(it); | ||||
} | } | ||||
} | } | ||||
{ | // Check the proof's validity. | ||||
// Reject invalid proof. | ProofValidationState state; | ||||
bool valid = [&](ProofValidationState &state) { | |||||
LOCK(cs_main); | LOCK(cs_main); | ||||
const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | ||||
return proof->verify(state, coins); | |||||
}(state); | |||||
ProofValidationState state; | if (!valid) { | ||||
if (!proof->verify(state, coins)) { | if (isOrphanState(state)) { | ||||
return peers.end(); | orphanProofs.addProof(proof); | ||||
} | } | ||||
// Reject invalid proof. | |||||
return peers.end(); | |||||
} | } | ||||
orphanProofs.removeProof(proof->getId()); | |||||
// New peer means new peerid! | // New peer means new peerid! | ||||
const PeerId peerid = nextPeerId++; | const PeerId peerid = nextPeerId++; | ||||
// Attach UTXOs to this proof. | // Attach UTXOs to this proof. | ||||
std::unordered_set<PeerId> conflicting_peerids; | std::unordered_set<PeerId> conflicting_peerids; | ||||
for (const auto &s : proof->getStakes()) { | for (const auto &s : proof->getStakes()) { | ||||
auto p = utxos.emplace(s.getStake().getUTXO(), peerid); | auto p = utxos.emplace(s.getStake().getUTXO(), peerid); | ||||
if (!p.second) { | if (!p.second) { | ||||
▲ Show 20 Lines • Show All 233 Lines • ▼ Show 20 Lines | std::vector<NodeId> PeerManager::getNodeIdsForPeer(PeerId peerId) const { | ||||
auto &nview = nodes.get<next_request_time>(); | auto &nview = nodes.get<next_request_time>(); | ||||
auto nodeRange = nview.equal_range(peerId); | auto nodeRange = nview.equal_range(peerId); | ||||
for (auto it = nodeRange.first; it != nodeRange.second; ++it) { | for (auto it = nodeRange.first; it != nodeRange.second; ++it) { | ||||
nodeids.emplace_back(it->nodeid); | nodeids.emplace_back(it->nodeid); | ||||
} | } | ||||
return nodeids; | return nodeids; | ||||
} | } | ||||
bool PeerManager::isOrphan(const ProofId &id) { | |||||
return orphanProofs.getProof(id) != nullptr; | |||||
} | |||||
} // namespace avalanche | } // namespace avalanche |