Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14864557
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
24 KB
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment