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/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 { | ||||
PeerId PeerManager::getPeer(const Proof &proof) { | PeerId PeerManager::getPeer(const Proof &proof) { | ||||
{ | |||||
// 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 it->peerid; | return it->peerid; | ||||
} | } | ||||
} | |||||
{ | { | ||||
// Reject invalid proof. | // Reject invalid proof. | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | ||||
ProofValidationState state; | ProofValidationState state; | ||||
if (!proof.verify(state, coins)) { | if (!proof.verify(state, coins)) { | ||||
return NO_PEER; | return NO_PEER; | ||||
} | } | ||||
} | } | ||||
// We have no peer for this proof, time to create it. | // New peer means new peerid! | ||||
const PeerId peerid = nextPeerId++; | const PeerId peerid = nextPeerId++; | ||||
// Attach UTXOs to this proof. | |||||
std::unordered_set<PeerId> conflicting_peerids; | |||||
for (const auto &s : proof.getStakes()) { | |||||
auto p = utxos.emplace(s.getStake().getUTXO(), peerid); | |||||
if (!p.second) { | |||||
// We have a collision with an existing proof. | |||||
conflicting_peerids.insert(p.first->second); | |||||
} | |||||
} | |||||
// For now, if there is a conflict, just ceanup the mess. | |||||
if (conflicting_peerids.size() > 0) { | |||||
for (const auto &s : proof.getStakes()) { | |||||
auto it = utxos.find(s.getStake().getUTXO()); | |||||
assert(it != utxos.end()); | |||||
// We need to delete that one. | |||||
if (it->second == peerid) { | |||||
utxos.erase(it); | |||||
} | |||||
} | |||||
return NO_PEER; | |||||
} | |||||
// We have no peer for this proof, time to create it. | |||||
auto inserted = peers.emplace(peerid, uint32_t(slots.size()), proof); | auto inserted = peers.emplace(peerid, uint32_t(slots.size()), proof); | ||||
assert(inserted.second); | assert(inserted.second); | ||||
const uint32_t score = proof.getScore(); | const uint32_t score = proof.getScore(); | ||||
const uint64_t start = slotCount; | const uint64_t start = slotCount; | ||||
slots.emplace_back(start, score, peerid); | slots.emplace_back(start, score, peerid); | ||||
slotCount = start + score; | slotCount = start + score; | ||||
return peerid; | return peerid; | ||||
Show All 19 Lines | bool PeerManager::removePeer(const PeerId peerid) { | ||||
// Remove nodes associated with this peer, unless their timeout is still | // Remove nodes associated with this peer, unless their timeout is still | ||||
// active. This ensure that we don't overquery them in case their are | // active. This ensure that we don't overquery them in case their are | ||||
// subsequently added to another peer. | // subsequently added to another peer. | ||||
auto &nview = nodes.get<next_request_time>(); | auto &nview = nodes.get<next_request_time>(); | ||||
nview.erase(nview.lower_bound(boost::make_tuple(peerid, TimePoint())), | nview.erase(nview.lower_bound(boost::make_tuple(peerid, TimePoint())), | ||||
nview.upper_bound(boost::make_tuple( | nview.upper_bound(boost::make_tuple( | ||||
peerid, std::chrono::steady_clock::now()))); | peerid, std::chrono::steady_clock::now()))); | ||||
// Release UTXOs attached to this proof. | |||||
for (const auto &s : it->proof.getStakes()) { | |||||
bool deleted = utxos.erase(s.getStake().getUTXO()) > 0; | |||||
assert(deleted); | |||||
} | |||||
peers.erase(it); | peers.erase(it); | ||||
return true; | return true; | ||||
} | } | ||||
bool PeerManager::addNode(NodeId nodeid, const Proof &proof, | bool PeerManager::addNode(NodeId nodeid, const Proof &proof, | ||||
const CPubKey &pubkey) { | const CPubKey &pubkey) { | ||||
const PeerId peerid = getPeer(proof); | const PeerId peerid = getPeer(proof); | ||||
if (peerid == NO_PEER) { | if (peerid == NO_PEER) { | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | std::vector<PeerId> invalidPeers; | ||||
invalidPeers.push_back(p.peerid); | invalidPeers.push_back(p.peerid); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
for (const auto &pid : invalidPeers) { | for (const auto &pid : invalidPeers) { | ||||
removePeer(pid); | removePeer(pid); | ||||
} | } | ||||
compact(); | |||||
} | } | ||||
} // namespace avalanche | } // namespace avalanche |