removes member functions from Slots used only for testing, and moves them to tests

This commit is contained in:
Vito
2025-05-28 16:35:41 +02:00
parent 15b43bda0d
commit ae38c2a2ce
2 changed files with 89 additions and 236 deletions

View File

@@ -17,8 +17,8 @@
*/
//==============================================================================
#include <test/jtx.h>
#include <test/jtx/Env.h>
#include <test/overlay/clock.h>
#include <xrpld/overlay/Message.h>
#include <xrpld/overlay/Peer.h>
@@ -33,8 +33,8 @@
#include <boost/thread.hpp>
#include <chrono>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <numeric>
#include <optional>
@@ -191,52 +191,6 @@ public:
}
};
/** Manually advanced clock. */
class ManualClock
{
public:
typedef uint64_t rep;
typedef std::milli period;
typedef std::chrono::duration<std::uint32_t, period> duration;
typedef std::chrono::time_point<ManualClock> time_point;
inline static bool const is_steady = false;
static void
advance(duration d) noexcept
{
now_ += d;
}
static void
randAdvance(milliseconds min, milliseconds max)
{
now_ += randDuration(min, max);
}
static void
reset() noexcept
{
now_ = time_point(seconds(0));
}
static time_point
now() noexcept
{
return now_;
}
static duration
randDuration(milliseconds min, milliseconds max)
{
return duration(milliseconds(rand_int(min.count(), max.count())));
}
explicit ManualClock() = default;
private:
inline static time_point now_ = time_point(seconds(0));
};
/** Simulate server's OverlayImpl */
class Overlay
{
@@ -249,8 +203,7 @@ public:
uint256 const& key,
PublicKey const& validator,
Peer::id_t id,
SquelchCB f,
protocol::MessageType type = protocol::mtVALIDATION) = 0;
SquelchCB f) = 0;
virtual void deleteIdlePeers(UnsquelchCB) = 0;
@@ -538,8 +491,14 @@ public:
std::uint16_t
inState(PublicKey const& validator, reduce_relay::PeerState state)
{
auto res = slots_.inState(validator, state);
return res ? *res : 0;
auto const& it = slots_.slots_.find(validator);
if (it != slots_.slots_.end())
return std::count_if(
it->second.peers_.begin(),
it->second.peers_.end(),
[&](auto const& it) { return (it.second.state == state); });
return 0;
}
void
@@ -547,11 +506,10 @@ public:
uint256 const& key,
PublicKey const& validator,
Peer::id_t id,
SquelchCB f,
protocol::MessageType type = protocol::mtVALIDATION) override
SquelchCB f) override
{
squelch_ = f;
slots_.updateSlotAndSquelch(key, validator, id, type);
slots_.updateSlotAndSquelch(key, validator, id, true);
}
void
@@ -632,40 +590,56 @@ public:
bool
isCountingState(PublicKey const& validator)
{
return slots_.inState(validator, reduce_relay::SlotState::Counting);
auto const& it = slots_.slots_.find(validator);
if (it != slots_.slots_.end())
return it->second.state_ == reduce_relay::SlotState::Counting;
return false;
}
std::set<id_t>
getSelected(PublicKey const& validator)
{
return slots_.getSelected(validator);
auto const& it = slots_.slots_.find(validator);
if (it == slots_.slots_.end())
return {};
std::set<id_t> r;
for (auto const& [id, info] : it->second.peers_)
if (info.state == reduce_relay::PeerState::Selected)
r.insert(id);
return r;
}
bool
isSelected(PublicKey const& validator, Peer::id_t peer)
{
auto selected = slots_.getSelected(validator);
auto selected = getSelected(validator);
return selected.find(peer) != selected.end();
}
id_t
getSelectedPeer(PublicKey const& validator)
{
auto selected = slots_.getSelected(validator);
auto selected = getSelected(validator);
assert(selected.size());
return *selected.begin();
}
std::unordered_map<
id_t,
std::tuple<
reduce_relay::PeerState,
std::uint16_t,
std::uint32_t,
std::uint32_t>>
std::unordered_map<id_t, reduce_relay::Slot<clock_type>::PeerInfo>
getPeers(PublicKey const& validator)
{
return slots_.getPeers(validator);
auto const& it = slots_.slots_.find(validator);
if (it == slots_.slots_.end())
return {};
auto r = std::
unordered_map<id_t, reduce_relay::Slot<clock_type>::PeerInfo>();
for (auto const& [id, info] : it->second.peers_)
r.emplace(std::make_pair(id, info));
return r;
}
std::uint16_t
@@ -684,6 +658,13 @@ private:
if (auto it = peers_.find(id); it != peers_.end())
squelch_(validator, it->second, squelchDuration);
}
void
squelchAll(PublicKey const& validator, std::uint32_t duration) override
{
for (auto const& [id, peer] : peers_)
squelch_(validator, peer, duration);
}
void
unsquelch(PublicKey const& validator, Peer::id_t id) const override
{
@@ -874,8 +855,7 @@ public:
for (auto& [_, v] : peers)
{
(void)_;
if (std::get<reduce_relay::PeerState>(v) ==
reduce_relay::PeerState::Squelched)
if (v.state == reduce_relay::PeerState::Squelched)
return false;
}
}
@@ -887,7 +867,7 @@ private:
std::vector<Validator> validators_;
};
class reduce_relay_test : public beast::unit_test::suite
class base_squelch_test : public beast::unit_test::suite
{
using Slot = reduce_relay::Slot<ManualClock>;
using id_t = Peer::id_t;
@@ -901,8 +881,7 @@ protected:
<< "num peers " << (int)network_.overlay().getNumPeers()
<< std::endl;
for (auto& [k, v] : peers)
std::cout << k << ":" << (int)std::get<reduce_relay::PeerState>(v)
<< " ";
std::cout << k << ":" << to_string(v.state) << " ";
std::cout << std::endl;
}
@@ -1074,7 +1053,10 @@ protected:
network_.overlay().isSelected(*event.key_, event.peer_);
auto peers = network_.overlay().getPeers(*event.key_);
auto d = reduce_relay::epoch<milliseconds>(now).count() -
std::get<3>(peers[event.peer_]);
reduce_relay::epoch<milliseconds>(
peers[event.peer_].lastMessage)
.count();
mustHandle = event.isSelected_ &&
d > milliseconds(reduce_relay::IDLED).count() &&
network_.overlay().inState(
@@ -1296,7 +1278,7 @@ protected:
[&](PublicKey const& key, PeerWPtr const& peer) {
unsquelched++;
});
auto peers = network_.overlay().getPeers(network_.validator(0));
BEAST_EXPECT(
unsquelched ==
MAX_PEERS -
@@ -1317,8 +1299,7 @@ protected:
BEAST_EXPECT(propagateAndSquelch(log, true, false));
auto peers = network_.overlay().getPeers(network_.validator(0));
auto it = std::find_if(peers.begin(), peers.end(), [&](auto it) {
return std::get<reduce_relay::PeerState>(it.second) ==
reduce_relay::PeerState::Squelched;
return it.second.state == reduce_relay::PeerState::Squelched;
});
assert(it != peers.end());
std::uint16_t unsquelched = 0;
@@ -1514,7 +1495,7 @@ vp_base_squelch_max_selected_peers=2
auto peers = network_.overlay().getPeers(network_.validator(0));
// first message changes Slot state to Counting and is not counted,
// hence '-1'.
BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
BEAST_EXPECT(peers[0].count == (nMessages - 1));
// add duplicate
uint256 key(nMessages - 1);
network_.overlay().updateSlotAndSquelch(
@@ -1524,7 +1505,7 @@ vp_base_squelch_max_selected_peers=2
[&](PublicKey const&, PeerWPtr, std::uint32_t) {});
// confirm the same number of messages
peers = network_.overlay().getPeers(network_.validator(0));
BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
BEAST_EXPECT(peers[0].count == (nMessages - 1));
// advance the clock
ManualClock::advance(reduce_relay::IDLED + seconds(1));
network_.overlay().updateSlotAndSquelch(
@@ -1534,7 +1515,7 @@ vp_base_squelch_max_selected_peers=2
[&](PublicKey const&, PeerWPtr, std::uint32_t) {});
peers = network_.overlay().getPeers(network_.validator(0));
// confirm message number increased
BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
BEAST_EXPECT(peers[0].count == nMessages);
});
}
@@ -1550,6 +1531,12 @@ vp_base_squelch_max_selected_peers=2
if (duration > maxDuration_)
maxDuration_ = duration;
}
void
squelchAll(PublicKey const&, std::uint32_t) override
{
}
void
unsquelch(PublicKey const&, Peer::id_t) const override
{
@@ -1582,10 +1569,7 @@ vp_base_squelch_max_selected_peers=2
std::uint64_t mid = m * 1000 + peer;
uint256 const message{mid};
slots.updateSlotAndSquelch(
message,
validator,
peer,
protocol::MessageType::mtVALIDATION);
message, validator, peer, true);
}
}
// make Slot's internal hash router expire all messages
@@ -1703,7 +1687,7 @@ vp_base_squelch_max_selected_peers=2
Network network_;
public:
reduce_relay_test()
base_squelch_test()
: env_(*this, jtx::envconfig([](std::unique_ptr<Config> cfg) {
cfg->VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = true;
cfg->VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS = 6;
@@ -1732,7 +1716,7 @@ public:
}
};
class reduce_relay_simulate_test : public reduce_relay_test
class base_squelch_simulate_test : public base_squelch_test
{
void
testRandom(bool log)
@@ -1748,8 +1732,8 @@ class reduce_relay_simulate_test : public reduce_relay_test
}
};
BEAST_DEFINE_TESTSUITE(reduce_relay, ripple_data, ripple);
BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, ripple_data, ripple);
BEAST_DEFINE_TESTSUITE(base_squelch, ripple_data, ripple);
BEAST_DEFINE_TESTSUITE_MANUAL(base_squelch_simulate, ripple_data, ripple);
} // namespace test

View File

@@ -29,17 +29,23 @@
#include <xrpl/basics/random.h>
#include <xrpl/beast/container/aged_unordered_map.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/PropertyStream.h>
#include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/messages.h>
#include <algorithm>
#include <chrono>
#include <optional>
#include <set>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
namespace ripple {
// used to make private members of Slots class accessible for testing
namespace test {
class enhanced_squelch_test;
class base_squelch_test;
class OverlaySim;
} // namespace test
namespace reduce_relay {
@@ -143,8 +149,10 @@ public:
template <typename clock_type>
class Slot final
{
private:
friend class Slots<clock_type>;
friend class test::enhanced_squelch_test;
friend class test::OverlaySim;
using id_t = Peer::id_t;
using time_point = typename clock_type::time_point;
@@ -215,32 +223,6 @@ private:
return lastSelected_;
}
/** Return number of peers in state */
std::uint16_t
inState(PeerState state) const;
/** Return number of peers not in state */
std::uint16_t
notInState(PeerState state) const;
/** Return Slot's state */
SlotState
getState() const
{
return state_;
}
/** Return selected peers */
std::set<id_t>
getSelected() const;
/** Get peers info. Return map of peer's state, count, squelch
* expiration milsec, and last message time milsec.
*/
std::
unordered_map<id_t, std::tuple<PeerState, uint16_t, uint32_t, uint32_t>>
getPeers() const;
/** Check if peers stopped relaying messages. If a peer is
* selected peer then call unsquelch handler for all
* currently squelched peers and switch the slot to
@@ -258,7 +240,6 @@ private:
std::chrono::seconds
getSquelchDuration(std::size_t npeers);
private:
/** Reset counts of peers in Selected or Counting state */
void
resetCounts();
@@ -584,65 +565,18 @@ Slot<clock_type>::initCounting()
resetCounts();
}
template <typename clock_type>
std::uint16_t
Slot<clock_type>::inState(PeerState state) const
{
return std::count_if(peers_.begin(), peers_.end(), [&](auto const& it) {
return (it.second.state == state);
});
}
template <typename clock_type>
std::uint16_t
Slot<clock_type>::notInState(PeerState state) const
{
return std::count_if(peers_.begin(), peers_.end(), [&](auto const& it) {
return (it.second.state != state);
});
}
template <typename clock_type>
std::set<typename Peer::id_t>
Slot<clock_type>::getSelected() const
{
std::set<id_t> r;
for (auto const& [id, info] : peers_)
if (info.state == PeerState::Selected)
r.insert(id);
return r;
}
template <typename clock_type>
std::unordered_map<
typename Peer::id_t,
std::tuple<PeerState, uint16_t, uint32_t, uint32_t>>
Slot<clock_type>::getPeers() const
{
using namespace std::chrono;
auto r = std::unordered_map<
id_t,
std::tuple<PeerState, std::uint16_t, std::uint32_t, std::uint32_t>>();
for (auto const& [id, info] : peers_)
r.emplace(std::make_pair(
id,
std::move(std::make_tuple(
info.state,
info.count,
epoch<milliseconds>(info.expire).count(),
epoch<milliseconds>(info.lastMessage).count()))));
return r;
}
/** Slots is a container for validator's Slot and handles Slot update
* when a message is received from a validator. It also handles Slot aging
* and checks for peers which are disconnected or stopped relaying the messages.
* and checks for peers which are disconnected or stopped relaying the
* messages.
*/
template <typename clock_type>
class Slots final
{
friend class test::enhanced_squelch_test;
friend class test::base_squelch_test;
friend class test::OverlaySim;
using time_point = typename clock_type::time_point;
using id_t = typename Peer::id_t;
using messages = beast::aged_unordered_map<
@@ -767,71 +701,6 @@ public:
*/
void
deleteIdlePeers();
/** Return number of peers in state */
std::optional<std::uint16_t>
inState(PublicKey const& validator, PeerState state) const
{
auto const& it = slots_.find(validator);
if (it != slots_.end())
return it->second.inState(state);
return {};
}
/** Return number of peers not in state */
std::optional<std::uint16_t>
notInState(PublicKey const& validator, PeerState state) const
{
auto const& it = slots_.find(validator);
if (it != slots_.end())
return it->second.notInState(state);
return {};
}
/** Return true if Slot is in state */
bool
inState(PublicKey const& validator, SlotState state) const
{
auto const& it = slots_.find(validator);
if (it != slots_.end())
return it->second.state_ == state;
return false;
}
/** Get selected peers */
std::set<id_t>
getSelected(PublicKey const& validator)
{
auto const& it = slots_.find(validator);
if (it != slots_.end())
return it->second.getSelected();
return {};
}
/** Get peers info. Return map of peer's state, count, and squelch
* expiration milliseconds.
*/
std::unordered_map<
typename Peer::id_t,
std::tuple<PeerState, uint16_t, uint32_t, std::uint32_t>>
getPeers(PublicKey const& validator)
{
auto const& it = slots_.find(validator);
if (it != slots_.end())
return it->second.getPeers();
return {};
}
/** Get Slot's state */
std::optional<SlotState>
getState(PublicKey const& validator)
{
auto const& it = slots_.find(validator);
if (it != slots_.end())
return it->second.getState();
return {};
}
/** Called when a peer is deleted. If the peer was selected to be the
* source of messages from the validator then squelched peers have to be
* unsquelched.