Changeset View
Changeset View
Standalone View
Standalone View
src/avalanche/peermanager.cpp
Show First 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | return peers.modify(it, [&](Peer &p) { | ||||
} | } | ||||
// We need to allocate this peer. | // We need to allocate this peer. | ||||
p.index = uint32_t(slots.size()); | p.index = uint32_t(slots.size()); | ||||
const uint32_t score = p.getScore(); | const uint32_t score = p.getScore(); | ||||
const uint64_t start = slotCount; | const uint64_t start = slotCount; | ||||
slots.emplace_back(start, score, it->peerid); | slots.emplace_back(start, score, it->peerid); | ||||
slotCount = start + score; | slotCount = start + score; | ||||
// Add to our allocated score when we allocate a new peer in the slots | |||||
connectedPeersScore += score; | |||||
}); | }); | ||||
} | } | ||||
bool PeerManager::removeNode(NodeId nodeid) { | bool PeerManager::removeNode(NodeId nodeid) { | ||||
auto it = nodes.find(nodeid); | auto it = nodes.find(nodeid); | ||||
if (it == nodes.end()) { | if (it == nodes.end()) { | ||||
return false; | return false; | ||||
} | } | ||||
Show All 30 Lines | if (!peers.modify(it, [&](Peer &p) { p.node_count = new_count; })) { | ||||
return false; | return false; | ||||
} | } | ||||
if (new_count > 0) { | if (new_count > 0) { | ||||
// We are done. | // We are done. | ||||
return true; | return true; | ||||
} | } | ||||
// There are no more node left, we need to cleanup. | // There are no more nodes left, we need to clean up. Subtract allocated | ||||
// score and remove from slots. | |||||
const size_t i = it->index; | const size_t i = it->index; | ||||
assert(i < slots.size()); | assert(i < slots.size()); | ||||
assert(connectedPeersScore >= slots[i].getScore()); | |||||
connectedPeersScore -= slots[i].getScore(); | |||||
if (i + 1 == slots.size()) { | if (i + 1 == slots.size()) { | ||||
slots.pop_back(); | slots.pop_back(); | ||||
slotCount = slots.empty() ? 0 : slots.back().getStop(); | slotCount = slots.empty() ? 0 : slots.back().getStop(); | ||||
} else { | } else { | ||||
fragmentation += slots[i].getScore(); | fragmentation += slots[i].getScore(); | ||||
slots[i] = slots[i].withPeerId(NO_PEER); | slots[i] = slots[i].withPeerId(NO_PEER); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | bool PeerManager::registerProof(const ProofRef &proof, | ||||
// New peer means new peerid! | // New peer means new peerid! | ||||
const PeerId peerid = nextPeerId++; | const PeerId peerid = nextPeerId++; | ||||
// We have no peer for this proof, time to create it. | // We have no peer for this proof, time to create it. | ||||
auto inserted = peers.emplace(peerid, proof, nextCooldownTimePoint); | auto inserted = peers.emplace(peerid, proof, nextCooldownTimePoint); | ||||
assert(inserted.second); | assert(inserted.second); | ||||
// Add to our registered score when adding to the peer list | |||||
totalPeersScore += proof->getScore(); | |||||
// If there are nodes waiting for this proof, add them | // If there are nodes waiting for this proof, add them | ||||
auto &pendingNodesView = pendingNodes.get<by_proofid>(); | auto &pendingNodesView = pendingNodes.get<by_proofid>(); | ||||
auto range = pendingNodesView.equal_range(proofid); | auto range = pendingNodesView.equal_range(proofid); | ||||
// We want to update the nodes then remove them from the pending set. That | // We want to update the nodes then remove them from the pending set. That | ||||
// will invalidate the range iterators, so we need to save the node ids | // will invalidate the range iterators, so we need to save the node ids | ||||
// first before we can loop over them. | // first before we can loop over them. | ||||
std::vector<NodeId> nodeids; | std::vector<NodeId> nodeids; | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | 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. | // Release UTXOs attached to this proof. | ||||
validProofPool.removeProof(it->getProofId()); | validProofPool.removeProof(it->getProofId()); | ||||
m_unbroadcast_proofids.erase(it->getProofId()); | m_unbroadcast_proofids.erase(it->getProofId()); | ||||
// Remove the peer from the PeerSet and remove its score from the registered | |||||
// score total. | |||||
assert(totalPeersScore >= it->getScore()); | |||||
totalPeersScore -= it->getScore(); | |||||
peers.erase(it); | peers.erase(it); | ||||
return true; | return true; | ||||
} | } | ||||
PeerId PeerManager::selectPeer() const { | PeerId PeerManager::selectPeer() const { | ||||
if (slots.empty() || slotCount == 0) { | if (slots.empty() || slotCount == 0) { | ||||
return NO_PEER; | return NO_PEER; | ||||
} | } | ||||
Show All 38 Lines | uint64_t PeerManager::compact() { | ||||
slotCount = prevStop; | slotCount = prevStop; | ||||
fragmentation = 0; | fragmentation = 0; | ||||
return saved; | return saved; | ||||
} | } | ||||
bool PeerManager::verify() const { | bool PeerManager::verify() const { | ||||
uint64_t prevStop = 0; | uint64_t prevStop = 0; | ||||
uint32_t scoreFromSlots = 0; | |||||
for (size_t i = 0; i < slots.size(); i++) { | for (size_t i = 0; i < slots.size(); i++) { | ||||
const Slot &s = slots[i]; | const Slot &s = slots[i]; | ||||
// Slots must be in correct order. | // Slots must be in correct order. | ||||
if (s.getStart() < prevStop) { | if (s.getStart() < prevStop) { | ||||
return false; | return false; | ||||
} | } | ||||
prevStop = s.getStop(); | prevStop = s.getStop(); | ||||
// If this is a dead slot, then nothing more needs to be checked. | // If this is a dead slot, then nothing more needs to be checked. | ||||
if (s.getPeerId() == NO_PEER) { | if (s.getPeerId() == NO_PEER) { | ||||
continue; | continue; | ||||
} | } | ||||
// We have a live slot, verify index. | // We have a live slot, verify index. | ||||
auto it = peers.find(s.getPeerId()); | auto it = peers.find(s.getPeerId()); | ||||
if (it == peers.end() || it->index != i) { | if (it == peers.end() || it->index != i) { | ||||
return false; | return false; | ||||
} | } | ||||
// Accumulate score across slots | |||||
scoreFromSlots += slots[i].getScore(); | |||||
} | |||||
// Score across slots must be the same as our allocated score | |||||
if (scoreFromSlots != connectedPeersScore) { | |||||
return false; | |||||
} | } | ||||
uint32_t scoreFromAllPeers = 0; | |||||
uint32_t scoreFromPeersWithNodes = 0; | |||||
std::unordered_set<COutPoint, SaltedOutpointHasher> peersUtxos; | std::unordered_set<COutPoint, SaltedOutpointHasher> peersUtxos; | ||||
for (const auto &p : peers) { | for (const auto &p : peers) { | ||||
// Accumulate the score across peers to compare with total known score | |||||
scoreFromAllPeers += p.getScore(); | |||||
// A peer should have a proof attached | // A peer should have a proof attached | ||||
if (!p.proof) { | if (!p.proof) { | ||||
return false; | return false; | ||||
} | } | ||||
// Check proof pool consistency | // Check proof pool consistency | ||||
for (const auto &ss : p.proof->getStakes()) { | for (const auto &ss : p.proof->getStakes()) { | ||||
const COutPoint &outpoint = ss.getStake().getUTXO(); | const COutPoint &outpoint = ss.getStake().getUTXO(); | ||||
Show All 34 Lines | for (const auto &p : peers) { | ||||
return false; | return false; | ||||
} | } | ||||
// If there are no nodes attached to this peer, then we are done. | // If there are no nodes attached to this peer, then we are done. | ||||
if (p.node_count == 0) { | if (p.node_count == 0) { | ||||
continue; | continue; | ||||
} | } | ||||
scoreFromPeersWithNodes += p.getScore(); | |||||
// The index must point to a slot refering to this peer. | // The index must point to a slot refering to this peer. | ||||
if (p.index >= slots.size() || slots[p.index].getPeerId() != p.peerid) { | if (p.index >= slots.size() || slots[p.index].getPeerId() != p.peerid) { | ||||
return false; | return false; | ||||
} | } | ||||
// If the score do not match, same thing. | // If the score do not match, same thing. | ||||
if (slots[p.index].getScore() != p.getScore()) { | if (slots[p.index].getScore() != p.getScore()) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
// Check our accumulated scores against our registred and allocated scores | |||||
if (scoreFromAllPeers != totalPeersScore) { | |||||
return false; | |||||
} | |||||
if (scoreFromPeersWithNodes != connectedPeersScore) { | |||||
return false; | |||||
} | |||||
// We checked the utxo consistency for all our peers utxos already, so if | // We checked the utxo consistency for all our peers utxos already, so if | ||||
// the pool size differs from the expected one there are dangling utxos. | // the pool size differs from the expected one there are dangling utxos. | ||||
if (validProofPool.size() != peersUtxos.size()) { | if (validProofPool.size() != peersUtxos.size()) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 70 Lines • Show Last 20 Lines |