Page MenuHomePhabricator

No OneTemporary

diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp
index 5389138d0..fdcdd7bc6 100644
--- a/src/avalanche/peermanager.cpp
+++ b/src/avalanche/peermanager.cpp
@@ -1,224 +1,270 @@
// Copyright (c) 2020 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <avalanche/peermanager.h>
#include <random.h>
#include <cassert>
PeerId PeerManager::addPeer(PeerId p, uint32_t score) {
auto inserted = peers.emplace(p, Peer(score, uint32_t(slots.size())));
assert(inserted.second);
const uint64_t start = slotCount;
slots.emplace_back(start, score, p);
slotCount = start + score;
return p;
}
bool PeerManager::removePeer(PeerId p) {
auto it = peers.find(p);
if (it == peers.end()) {
return false;
}
size_t i = it->second.index;
assert(i < slots.size());
if (i + 1 == slots.size()) {
slots.pop_back();
slotCount = slots.empty() ? 0 : slots.back().getStop();
} else {
fragmentation += slots[i].getScore();
slots[i] = slots[i].withPeerId(NO_PEER);
}
peers.erase(it);
return true;
}
bool PeerManager::rescorePeer(PeerId p, uint32_t score) {
auto it = peers.find(p);
if (it == peers.end()) {
return false;
}
size_t i = it->second.index;
assert(i < slots.size());
// Update the peer's score.
it->second.score = score;
// Update the slot allocation to reflect the new score.
const uint64_t start = slots[i].getStart();
// If this is the last element, we can extend/shrink easily.
if (i + 1 == slots.size()) {
slots[i] = slots[i].withScore(score);
slotCount = slots[i].getStop();
return true;
}
const uint64_t stop = start + score;
const uint64_t nextStart = slots[i + 1].getStart();
// We can extend in place.
if (stop <= nextStart) {
fragmentation += (slots[i].getStop() - stop);
slots[i] = slots[i].withScore(score);
return true;
}
// So we need to insert a new entry.
fragmentation += slots[i].getScore();
slots[i] = slots[i].withPeerId(NO_PEER);
it->second.index = uint32_t(slots.size());
const uint64_t newStart = slotCount;
slots.emplace_back(newStart, score, p);
slotCount = newStart + score;
return true;
}
+bool PeerManager::addNodeToPeer(PeerId peerid, NodeId nodeid, CPubKey pubkey) {
+ auto pit = peers.find(peerid);
+ if (pit == peers.end()) {
+ return false;
+ }
+
+ auto nit = nodes.find(nodeid);
+ if (nit == nodes.end()) {
+ return nodes.emplace(nodeid, peerid, std::move(pubkey)).second;
+ }
+
+ // We actually have this node already, we need to update it.
+ return nodes.modify(nit, [&](Node &n) {
+ n.peerid = peerid;
+ n.pubkey = std::move(pubkey);
+ });
+}
+
+NodeId PeerManager::getSuitableNodeToQuery() {
+ for (int retry = 0; retry < SELECT_NODE_MAX_RETRY; retry++) {
+ const PeerId p = selectPeer();
+
+ // If we cannot find a peer, it may be due to the fact that it is
+ // unlikely due to high fragmentation, so compact and retry.
+ if (p == NO_PEER) {
+ compact();
+ continue;
+ }
+
+ // See if that peer has an available node.
+ auto it = nodes.get<next_request_time>().lower_bound(
+ boost::make_tuple(p, TimePoint()));
+ if (it != nodes.get<next_request_time>().end() && it->peerid == p &&
+ it->nextRequestTime <= std::chrono::steady_clock::now()) {
+ return it->nodeid;
+ }
+ }
+
+ return NO_NODE;
+}
+
PeerId PeerManager::selectPeer() const {
if (slots.empty() || slotCount == 0) {
return NO_PEER;
}
const uint64_t max = slotCount;
for (int retry = 0; retry < SELECT_PEER_MAX_RETRY; retry++) {
size_t i = selectPeerImpl(slots, GetRand(max), max);
if (i != NO_PEER) {
return i;
}
}
return NO_PEER;
}
uint64_t PeerManager::compact() {
+ // There is nothing to compact.
+ if (fragmentation == 0) {
+ return 0;
+ }
+
// Shrink the vector to the expected size.
while (slots.size() > peers.size()) {
slots.pop_back();
}
uint64_t prevStop = 0;
uint32_t i = 0;
for (auto &pair : peers) {
PeerId pid = pair.first;
Peer &p = pair.second;
slots[i] = Slot(prevStop, p.score, pid);
prevStop = slots[i].getStop();
p.index = i++;
}
const uint64_t saved = slotCount - prevStop;
slotCount = prevStop;
fragmentation = 0;
return saved;
}
bool PeerManager::verify() const {
uint64_t prevStop = 0;
for (size_t i = 0; i < slots.size(); i++) {
const Slot &s = slots[i];
// Slots must be in correct order.
if (s.getStart() < prevStop) {
return false;
}
prevStop = s.getStop();
// If this is a dead slot, then nothing more needs to be checked.
if (s.getPeerId() == NO_PEER) {
continue;
}
// We have a live slot, verify index.
auto it = peers.find(s.getPeerId());
if (it == peers.end() || it->second.index != i) {
return false;
}
}
for (const auto &pair : peers) {
auto p = pair.first;
auto i = pair.second.index;
auto s = pair.second.score;
// The index must point to a slot refering to this peer.
if (i >= slots.size() || slots[i].getPeerId() != p) {
return false;
}
// If the score do not match, same thing.
if (slots[i].getScore() != s) {
return false;
}
}
return true;
}
PeerId selectPeerImpl(const std::vector<Slot> &slots, const uint64_t slot,
const uint64_t max) {
assert(slot <= max);
size_t begin = 0, end = slots.size();
uint64_t bottom = 0, top = max;
// Try to find the slot using dichotomic search.
while ((end - begin) > 8) {
// The slot we picked in not allocated.
if (slot < bottom || slot >= top) {
return NO_PEER;
}
// Guesstimate the position of the slot.
size_t i = begin + ((slot - bottom) * (end - begin) / (top - bottom));
assert(begin <= i && i < end);
// We have a match.
if (slots[i].contains(slot)) {
return slots[i].getPeerId();
}
// We undershooted.
if (slots[i].precedes(slot)) {
begin = i + 1;
if (begin >= end) {
return NO_PEER;
}
bottom = slots[begin].getStart();
continue;
}
// We overshooted.
if (slots[i].follows(slot)) {
end = i;
top = slots[end].getStart();
continue;
}
// We have an unalocated slot.
return NO_PEER;
}
// Enough of that nonsense, let fallback to linear search.
for (size_t i = begin; i < end; i++) {
// We have a match.
if (slots[i].contains(slot)) {
return slots[i].getPeerId();
}
}
// We failed to find a slot, retry.
return NO_PEER;
}
diff --git a/src/avalanche/peermanager.h b/src/avalanche/peermanager.h
index bd0ce20c6..23f6d7cdd 100644
--- a/src/avalanche/peermanager.h
+++ b/src/avalanche/peermanager.h
@@ -1,101 +1,157 @@
// Copyright (c) 2020 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_AVALANCHE_PEERMANAGER_H
#define BITCOIN_AVALANCHE_PEERMANAGER_H
+#include <net.h>
+#include <pubkey.h>
+
+#include <boost/multi_index/composite_key.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index_container.hpp>
+
+#include <chrono>
#include <cstdint>
#include <unordered_map>
#include <vector>
using PeerId = uint32_t;
-static constexpr PeerId NO_PEER = ~uint32_t(0);
+static constexpr PeerId NO_PEER = -1;
struct Slot {
private:
uint64_t start;
uint32_t score;
PeerId peerid;
public:
Slot(uint64_t startIn, uint32_t scoreIn, PeerId peeridIn)
: start(startIn), score(scoreIn), peerid(peeridIn) {}
Slot withStart(uint64_t startIn) const {
return Slot(startIn, score, peerid);
}
Slot withScore(uint64_t scoreIn) const {
return Slot(start, scoreIn, peerid);
}
Slot withPeerId(PeerId peeridIn) const {
return Slot(start, score, peeridIn);
}
uint64_t getStart() const { return start; }
uint64_t getStop() const { return start + score; }
uint32_t getScore() const { return score; }
- uint32_t getPeerId() const { return peerid; }
+ PeerId getPeerId() const { return peerid; }
bool contains(uint64_t slot) const {
return getStart() <= slot && slot < getStop();
}
bool precedes(uint64_t slot) const { return slot >= getStop(); }
bool follows(uint64_t slot) const { return getStart() > slot; }
};
+struct next_request_time {};
+
class PeerManager {
std::vector<Slot> slots;
uint64_t slotCount = 0;
uint64_t fragmentation = 0;
/**
* Several nodes can make an avalanche peer. In this case, all nodes are
* considered interchangeable parts of the same peer.
*/
struct Peer {
uint32_t score;
uint32_t index;
Peer(uint32_t score_, uint32_t index_) : score(score_), index(index_) {}
};
PeerId nextPeerId = 0;
std::unordered_map<PeerId, Peer> peers;
+ using TimePoint = std::chrono::time_point<std::chrono::steady_clock>;
+
+ struct Node {
+ NodeId nodeid;
+ PeerId peerid;
+ TimePoint nextRequestTime;
+ CPubKey pubkey;
+
+ Node(NodeId nodeid_, PeerId peerid_, CPubKey pubkey_)
+ : nodeid(nodeid_), peerid(peerid_),
+ nextRequestTime(std::chrono::steady_clock::now()),
+ pubkey(std::move(pubkey_)) {}
+ };
+
+ using NodeSet = boost::multi_index_container<
+ Node,
+ boost::multi_index::indexed_by<
+ // index by nodeid
+ boost::multi_index::hashed_unique<
+ boost::multi_index::member<Node, NodeId, &Node::nodeid>>,
+ // sorted by peerid/nextRequestTime
+ boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<next_request_time>,
+ boost::multi_index::composite_key<
+ Node,
+ boost::multi_index::member<Node, PeerId, &Node::peerid>,
+ boost::multi_index::member<Node, TimePoint,
+ &Node::nextRequestTime>>>>>;
+
+ NodeSet nodes;
+
static constexpr int SELECT_PEER_MAX_RETRY = 3;
+ static constexpr int SELECT_NODE_MAX_RETRY = 3;
public:
+ /**
+ * Peer API.
+ */
PeerId addPeer(uint32_t score) { return addPeer(nextPeerId++, score); }
bool removePeer(PeerId p);
bool rescorePeer(PeerId p, uint32_t score);
+ /**
+ * Node API.
+ */
+ bool addNodeToPeer(PeerId peerid, NodeId nodeid, CPubKey pubkey);
+ NodeId getSuitableNodeToQuery();
+
+ /**
+ * Exposed for tests.
+ */
PeerId selectPeer() const;
/**
* Trigger maintenance of internal datastructures.
* Returns how much slot space was saved after compaction.
*/
uint64_t compact();
/**
* Perform consistency check on internal data structures.
* Mostly useful for tests.
*/
bool verify() const;
// Accssors.
uint64_t getSlotCount() const { return slotCount; }
uint64_t getFragmentation() const { return fragmentation; }
private:
PeerId addPeer(PeerId peerid, uint32_t score);
};
/**
* This is an internal method that is exposed for testing purposes.
*/
PeerId selectPeerImpl(const std::vector<Slot> &slots, const uint64_t slot,
const uint64_t max);
#endif // BITCOIN_AVALANCHE_PEERMANAGER_H
diff --git a/src/avalanche/test/peermanager_tests.cpp b/src/avalanche/test/peermanager_tests.cpp
index 4c3bc545e..b848cc36c 100644
--- a/src/avalanche/test/peermanager_tests.cpp
+++ b/src/avalanche/test/peermanager_tests.cpp
@@ -1,353 +1,371 @@
// Copyright (c) 2020 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <avalanche/peermanager.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(peermanager_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(select_peer_linear) {
// No peers.
BOOST_CHECK_EQUAL(selectPeerImpl({}, 0, 0), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl({}, 1, 3), NO_PEER);
// One peer
const std::vector<Slot> oneslot = {{100, 100, 23}};
// Undershoot
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 0, 300), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 42, 300), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 99, 300), NO_PEER);
// Nailed it
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 100, 300), 23);
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 142, 300), 23);
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 199, 300), 23);
// Overshoot
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 200, 300), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 242, 300), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(oneslot, 299, 300), NO_PEER);
// Two peers
const std::vector<Slot> twoslots = {{100, 100, 69}, {300, 100, 42}};
// Undershoot
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 0, 500), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 42, 500), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 99, 500), NO_PEER);
// First entry
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 100, 500), 69);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 142, 500), 69);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 199, 500), 69);
// In betwenn
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 200, 500), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 242, 500), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 299, 500), NO_PEER);
// Second entry
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 300, 500), 42);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 342, 500), 42);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 399, 500), 42);
// Overshoot
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 400, 500), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 442, 500), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(twoslots, 499, 500), NO_PEER);
}
BOOST_AUTO_TEST_CASE(select_peer_dichotomic) {
std::vector<Slot> slots;
// 100 peers of size 1 with 1 empty element apart.
uint64_t max = 1;
for (int i = 0; i < 100; i++) {
slots.emplace_back(max, 1, i);
max += 2;
}
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 4, max), NO_PEER);
// Check that we get what we expect.
for (int i = 0; i < 100; i++) {
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 2 * i, max), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 2 * i + 1, max), i);
}
BOOST_CHECK_EQUAL(selectPeerImpl(slots, max, max), NO_PEER);
// Update the slots to be heavily skewed toward the last element.
slots[99] = slots[99].withScore(101);
max = slots[99].getStop();
BOOST_CHECK_EQUAL(max, 300);
for (int i = 0; i < 100; i++) {
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 2 * i, max), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 2 * i + 1, max), i);
}
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 200, max), 99);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 256, max), 99);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 299, max), 99);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 300, max), NO_PEER);
// Update the slots to be heavily skewed toward the first element.
for (int i = 0; i < 100; i++) {
slots[i] = slots[i].withStart(slots[i].getStart() + 100);
}
slots[0] = Slot(1, slots[0].getStop() - 1, slots[0].getPeerId());
slots[99] = slots[99].withScore(1);
max = slots[99].getStop();
BOOST_CHECK_EQUAL(max, 300);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 0, max), NO_PEER);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 1, max), 0);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 42, max), 0);
for (int i = 0; i < 100; i++) {
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 100 + 2 * i + 1, max), i);
BOOST_CHECK_EQUAL(selectPeerImpl(slots, 100 + 2 * i + 2, max), NO_PEER);
}
}
BOOST_AUTO_TEST_CASE(select_peer_random) {
for (int c = 0; c < 1000; c++) {
size_t size = InsecureRandBits(10) + 1;
std::vector<Slot> slots;
slots.reserve(size);
uint64_t max = InsecureRandBits(3);
auto next = [&]() {
uint64_t r = max;
max += InsecureRandBits(3);
return r;
};
for (size_t i = 0; i < size; i++) {
const uint64_t start = next();
const uint32_t score = InsecureRandBits(3);
max += score;
slots.emplace_back(start, score, i);
}
for (int k = 0; k < 100; k++) {
uint64_t s = InsecureRandRange(max);
auto i = selectPeerImpl(slots, s, max);
// /!\ Because of the way we construct the vector, the peer id is
// always the index. This might not be the case in practice.
BOOST_CHECK(i == NO_PEER || slots[i].contains(s));
}
}
}
BOOST_AUTO_TEST_CASE(add_peer) {
// No peers.
PeerManager pm;
BOOST_CHECK_EQUAL(pm.selectPeer(), NO_PEER);
// One peer, we always return it.
PeerId peer0 = pm.addPeer(100);
BOOST_CHECK_EQUAL(pm.selectPeer(), peer0);
// Two peers, verify ratio.
PeerId peer1 = pm.addPeer(200);
std::unordered_map<PeerId, int> results = {};
for (int i = 0; i < 10000; i++) {
size_t p = pm.selectPeer();
BOOST_CHECK(p == peer0 || p == peer1);
results[p]++;
}
BOOST_CHECK(abs(2 * results[0] - results[1]) < 500);
// Three peers, verify ratio.
PeerId peer2 = pm.addPeer(100);
results.clear();
for (int i = 0; i < 10000; i++) {
size_t p = pm.selectPeer();
BOOST_CHECK(p == peer0 || p == peer1 || p == peer2);
results[p]++;
}
BOOST_CHECK(abs(results[0] - results[1] + results[2]) < 500);
}
BOOST_AUTO_TEST_CASE(remove_peer) {
// No peers.
PeerManager pm;
BOOST_CHECK_EQUAL(pm.selectPeer(), NO_PEER);
// Add 4 peers.
std::array<PeerId, 8> peerids;
for (int i = 0; i < 4; i++) {
peerids[i] = pm.addPeer(100);
}
BOOST_CHECK_EQUAL(pm.getSlotCount(), 400);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 0);
for (int i = 0; i < 100; i++) {
PeerId p = pm.selectPeer();
BOOST_CHECK(p == peerids[0] || p == peerids[1] || p == peerids[2] ||
p == peerids[3]);
}
// Remove one peer, it nevers show up now.
BOOST_CHECK(pm.removePeer(peerids[2]));
BOOST_CHECK_EQUAL(pm.getSlotCount(), 400);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 100);
// Make sure we compact to never get NO_PEER.
BOOST_CHECK_EQUAL(pm.compact(), 100);
BOOST_CHECK(pm.verify());
BOOST_CHECK_EQUAL(pm.getSlotCount(), 300);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 0);
for (int i = 0; i < 100; i++) {
PeerId p = pm.selectPeer();
BOOST_CHECK(p == peerids[0] || p == peerids[1] || p == peerids[3]);
}
// Add 4 more peers.
for (int i = 0; i < 4; i++) {
peerids[i + 4] = pm.addPeer(100);
}
BOOST_CHECK_EQUAL(pm.getSlotCount(), 700);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 0);
BOOST_CHECK(pm.removePeer(peerids[0]));
BOOST_CHECK_EQUAL(pm.getSlotCount(), 700);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 100);
// Removing the last entry do not increase fragmentation.
BOOST_CHECK(pm.removePeer(peerids[7]));
BOOST_CHECK_EQUAL(pm.getSlotCount(), 600);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 100);
// Make sure we compact to never get NO_PEER.
BOOST_CHECK_EQUAL(pm.compact(), 100);
BOOST_CHECK(pm.verify());
BOOST_CHECK_EQUAL(pm.getSlotCount(), 500);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 0);
for (int i = 0; i < 100; i++) {
PeerId p = pm.selectPeer();
BOOST_CHECK(p == peerids[1] || p == peerids[3] || p == peerids[4] ||
p == peerids[5] || p == peerids[6]);
}
// Removing non existent peers fails.
BOOST_CHECK(!pm.removePeer(peerids[0]));
BOOST_CHECK(!pm.removePeer(peerids[2]));
BOOST_CHECK(!pm.removePeer(peerids[7]));
BOOST_CHECK(!pm.removePeer(NO_PEER));
}
BOOST_AUTO_TEST_CASE(rescore_peer, *boost::unit_test::timeout(5)) {
// No peers.
PeerManager pm;
BOOST_CHECK_EQUAL(pm.selectPeer(), NO_PEER);
// Add 4 peers.
std::array<PeerId, 4> peerids;
for (int i = 0; i < 4; i++) {
peerids[i] = pm.addPeer(100);
}
BOOST_CHECK_EQUAL(pm.getSlotCount(), 400);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 0);
for (int i = 0; i < 100; i++) {
PeerId p = pm.selectPeer();
BOOST_CHECK(p == peerids[0] || p == peerids[1] || p == peerids[2] ||
p == peerids[3]);
}
// Set one peer's score to 0, it nevers show up now.
BOOST_CHECK(pm.rescorePeer(peerids[1], 0));
BOOST_CHECK_EQUAL(pm.getSlotCount(), 400);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 100);
for (int i = 0; i < 100; i++) {
PeerId p = pm.selectPeer();
BOOST_CHECK(p == peerids[0] || p == peerids[2] || p == peerids[3] ||
p == NO_PEER);
}
// "resurrect" the peer.
BOOST_CHECK(pm.rescorePeer(peerids[1], 100));
BOOST_CHECK_EQUAL(pm.getSlotCount(), 400);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 0);
while (true) {
PeerId p = pm.selectPeer();
BOOST_CHECK(p == peerids[0] || p == peerids[1] || p == peerids[2] ||
p == peerids[3]);
// Make sure peer 1 reappeared.
if (p == peerids[1]) {
break;
}
}
// Grow the peer to a point where it needs to be reallocated.
BOOST_CHECK(pm.rescorePeer(peerids[1], 200));
BOOST_CHECK_EQUAL(pm.getSlotCount(), 600);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 100);
for (int i = 0; i < 25; i++) {
while (true) {
PeerId p = pm.selectPeer();
BOOST_CHECK(p == peerids[0] || p == peerids[1] || p == peerids[2] ||
p == peerids[3] || p == NO_PEER);
// Make sure peer 1 reappeared.
if (p == peerids[1]) {
break;
}
}
}
// Compact the peer manager.
BOOST_CHECK_EQUAL(pm.compact(), 100);
BOOST_CHECK(pm.verify());
BOOST_CHECK_EQUAL(pm.getSlotCount(), 500);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 0);
}
BOOST_AUTO_TEST_CASE(compact_slots) {
PeerManager pm;
// Add 4 peers.
std::array<PeerId, 4> peerids;
for (int i = 0; i < 4; i++) {
peerids[i] = pm.addPeer(100);
}
// Remove all peers.
for (auto p : peerids) {
pm.removePeer(p);
}
BOOST_CHECK_EQUAL(pm.getSlotCount(), 300);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 300);
for (int i = 0; i < 100; i++) {
BOOST_CHECK_EQUAL(pm.selectPeer(), NO_PEER);
}
BOOST_CHECK_EQUAL(pm.compact(), 300);
BOOST_CHECK(pm.verify());
BOOST_CHECK_EQUAL(pm.getSlotCount(), 0);
BOOST_CHECK_EQUAL(pm.getFragmentation(), 0);
}
+BOOST_AUTO_TEST_CASE(add_and_get_node) {
+ PeerManager pm;
+
+ // Create one peer.
+ PeerId peerid = pm.addPeer(100);
+ BOOST_CHECK_EQUAL(pm.getSuitableNodeToQuery(), NO_NODE);
+
+ // Add 4 nodes.
+ for (int i = 0; i < 4; i++) {
+ BOOST_CHECK(pm.addNodeToPeer(peerid, i, CPubKey()));
+ }
+
+ for (int i = 0; i < 100; i++) {
+ NodeId n = pm.getSuitableNodeToQuery();
+ BOOST_CHECK((n >= 0 && n < 4) || n == NO_PEER);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()

File Metadata

Mime Type
text/x-diff
Expires
Wed, May 21, 20:34 (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5865888
Default Alt Text
(24 KB)

Event Timeline