2#include <test/jtx/Env.h>
4#include <xrpld/overlay/Message.h>
5#include <xrpld/overlay/Peer.h>
6#include <xrpld/overlay/Slot.h>
7#include <xrpld/overlay/Squelch.h>
8#include <xrpld/overlay/detail/Handshake.h>
10#include <xrpl/basics/random.h>
11#include <xrpl/beast/unit_test.h>
12#include <xrpl/protocol/SecretKey.h>
13#include <xrpl/protocol/messages.h>
15#include <boost/thread.hpp>
234 protocol::MessageType type = protocol::mtVALIDATION) = 0;
269 peer->onMessage(m, f);
311 protocol::TMValidation v;
312 v.set_validation(
"validation");
366 for (
auto id : peers)
422 it->second->up(
true);
430 it->second->up(
false);
512 :
slots_(app.logs(), *this, app.config()),
logs_(app.logs())
530 return res ? *res : 0;
539 protocol::MessageType type = protocol::mtVALIDATION)
override
549 slots_.deletePeer(
id,
true);
608 for (
auto& [
id, _] :
peers_)
636 return selected.find(peer) != selected.end();
643 assert(selected.size());
644 return *selected.begin();
767 return v.id() == validatorId;
788 squelch.clear_validatorpubkey();
802 auto size = max - min;
818 bool resetClock =
true)
829 for (
int m = 0; m < nMessages; ++m)
862 for (
auto& [_, v] : peers)
891 for (
auto& [k, v] : peers)
910 auto sp = peerPtr.
lock();
950 bool squelched =
false;
967 str <<
" selected: ";
968 for (
auto s : selected)
972 << (double)reduce_relay::epoch<milliseconds>(now)
975 <<
" random, squelched, validator: " <<
validator.id()
980 countingState ==
false &&
992 events[event].cnt_++;
993 events[event].validator_ =
validator.id();
995 events[event].peer_ = link.
peerId();
997 events[event].time_ = now;
1002 events[event].isSelected_ =
1007 events[event].isSelected_ =
1025 if (event.isSelected_)
1026 sendSquelch(v, peerPtr, {});
1027 event.handled_ =
true;
1035 (
event.isSelected_ ==
false && !
event.handled_) ||
1036 (event.isSelected_ ==
true &&
1037 (event.handled_ || allCounting));
1038 BEAST_EXPECT(handled);
1040 event.isSelected_ =
false;
1041 event.handledCnt_ += handled;
1042 event.handled_ =
false;
1058 bool mustHandle =
false;
1059 if (event.state_ ==
State::On && BEAST_EXPECT(event.key_))
1064 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1066 mustHandle =
event.isSelected_ &&
1071 peers.find(event.peer_) != peers.end();
1075 event.handled_ =
true;
1076 if (mustHandle && v == event.key_)
1078 event.state_ = State::WaitReset;
1079 sendSquelch(validator, ptr, {});
1084 (!event.handled_ && !mustHandle);
1085 BEAST_EXPECT(handled);
1093 BEAST_EXPECT(handled);
1095 event.isSelected_ =
false;
1096 event.handledCnt_ += handled;
1097 event.handled_ =
false;
1102 auto&
down = events[EventType::LinkDown];
1103 auto& disconnected = events[EventType::PeerDisconnected];
1105 BEAST_EXPECT(
down.handledCnt_ >=
down.cnt_ - 1);
1107 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1111 <<
" peer disconnect count: " << disconnected.cnt_ <<
"/"
1112 << disconnected.handledCnt_;
1118 auto countingState = network_.overlay().isCountingState(
validator);
1119 BEAST_EXPECT(countingState == isCountingState);
1120 return countingState == isCountingState;
1138 doTest(
"Initial Round", log, [
this](
bool log) {
1139 BEAST_EXPECT(propagateAndSquelch(log));
1149 doTest(
"Peer Unsquelched Too Soon", log, [
this](
bool log) {
1150 BEAST_EXPECT(propagateNoSquelch(log, 1,
false,
false,
false));
1160 ManualClock::advance(
seconds(601));
1161 doTest(
"Peer Unsquelched", log, [
this](
bool log) {
1162 BEAST_EXPECT(propagateNoSquelch(log, 2,
true,
true,
false));
1180 sendSquelch(key, peerPtr,
duration);
1189 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1197 auto selected = network_.overlay().getSelected(network_.validator(0));
1200 env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1201 BEAST_EXPECT(n == 1);
1202 auto res = checkCounting(network_.validator(0),
false);
1204 return n == 1 && res;
1214 bool resetClock =
true)
1216 bool squelched =
false;
1225 BEAST_EXPECT(
false);
1232 auto res = checkCounting(network_.validator(0), countingState);
1233 return !squelched && res;
1242 doTest(
"New Peer", log, [
this](
bool log) {
1243 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1245 BEAST_EXPECT(propagateNoSquelch(log, 1,
true,
false,
false));
1254 doTest(
"Selected Peer Disconnects", log, [
this](
bool log) {
1255 ManualClock::advance(
seconds(601));
1256 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1257 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1259 network_.overlay().deletePeer(
1268 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1269 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1278 doTest(
"Selected Peer Stops Relaying", log, [
this](
bool log) {
1279 ManualClock::advance(
seconds(601));
1280 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1283 network_.overlay().deleteIdlePeers(
1287 auto peers = network_.overlay().getPeers(network_.validator(0));
1293 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1294 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1303 doTest(
"Squelched Peer Disconnects", log, [
this](
bool log) {
1304 ManualClock::advance(
seconds(601));
1305 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1306 auto peers = network_.overlay().getPeers(network_.validator(0));
1307 auto it =
std::find_if(peers.begin(), peers.end(), [&](
auto it) {
1308 return std::get<reduce_relay::PeerState>(it.second) ==
1309 reduce_relay::PeerState::Squelched;
1311 assert(it != peers.end());
1313 network_.overlay().deletePeer(
1317 BEAST_EXPECT(unsquelched == 0);
1318 BEAST_EXPECT(checkCounting(network_.validator(0),
false));
1325 doTest(
"Test Config - squelch enabled (legacy)", log, [&](
bool log) {
1337 doTest(
"Test Config - squelch disabled (legacy)", log, [&](
bool log) {
1350 toLoad = R
"rippleConfig(
1358 doTest(
"Test Config - squelch enabled", log, [&](
bool log) {
1363vp_base_squelch_enable=1
1370 doTest(
"Test Config - squelch disabled", log, [&](
bool log) {
1375vp_base_squelch_enable=0
1382 doTest(
"Test Config - legacy and new", log, [&](
bool log) {
1387vp_base_squelch_enable=0
1392 auto const expectedError =
1393 "Invalid reduce_relay"
1394 " cannot specify both vp_base_squelch_enable and vp_enable "
1396 "vp_enable was deprecated and replaced by "
1397 "vp_base_squelch_enable";
1408 BEAST_EXPECT(error == expectedError);
1411 doTest(
"Test Config - max selected peers", log, [&](
bool log) {
1423 toLoad = R"rippleConfig(
1425vp_base_squelch_max_selected_peers=6
1433 toLoad = R"rippleConfig(
1435vp_base_squelch_max_selected_peers=2
1439 auto const expectedError =
1440 "Invalid reduce_relay"
1441 " vp_base_squelch_max_selected_peers must be "
1442 "greater than or equal to 3";
1452 BEAST_EXPECT(error == expectedError);
1459 doTest(
"BaseSquelchReady", log, [&](
bool log) {
1460 ManualClock::reset();
1461 auto createSlots = [&](
bool baseSquelchEnabled)
1463 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
1466 env_.app().logs(), network_.overlay(), env_.app().config());
1469 BEAST_EXPECT(!createSlots(
false).baseSquelchReady());
1473 BEAST_EXPECT(!createSlots(
true).baseSquelchReady());
1478 BEAST_EXPECT(createSlots(
true).baseSquelchReady());
1482 BEAST_EXPECT(!createSlots(
false).baseSquelchReady());
1489 doTest(
"Duplicate Message", log, [&](
bool log) {
1493 for (
int i = 0; i < nMessages; i++)
1496 network_.overlay().updateSlotAndSquelch(
1498 network_.validator(0),
1502 auto peers = network_.overlay().getPeers(network_.validator(0));
1505 BEAST_EXPECT(
std::get<1>(peers[0]) == (nMessages - 1));
1508 network_.overlay().updateSlotAndSquelch(
1510 network_.validator(0),
1514 peers = network_.overlay().getPeers(network_.validator(0));
1515 BEAST_EXPECT(
std::get<1>(peers[0]) == (nMessages - 1));
1518 network_.overlay().updateSlotAndSquelch(
1520 network_.validator(0),
1523 peers = network_.overlay().getPeers(network_.validator(0));
1551 doTest(
"Random Squelch", l, [&](
bool l) {
1555 auto run = [&](
int npeers) {
1558 env_.app().logs(), handler, env_.app().config());
1566 for (
int peer = 0; peer < npeers; peer++)
1576 protocol::MessageType::mtVALIDATION);
1580 ManualClock::advance(
hours(1));
1583 using namespace reduce_relay;
1588 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1589 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1592 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1593 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1602 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1603 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1605 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1607 "warning: squelch duration is low",
1615 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1616 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1617 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1619 "warning: squelch duration is low",
1630 doTest(
"Handshake", log, [&](
bool log) {
1631 auto setEnv = [&](
bool enable) {
1634 str <<
"[reduce_relay]\n"
1635 <<
"vp_enable=" << enable <<
"\n"
1636 <<
"[compression]\n"
1639 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
1644 auto handshake = [&](
int outboundEnable,
int inboundEnable) {
1646 boost::asio::ip::make_address(
"172.1.1.100");
1648 setEnv(outboundEnable);
1651 env_.app().config().COMPRESSION,
1653 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1654 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE);
1656 http_request.version(request.version());
1657 http_request.base() = request.base();
1660 auto const peerEnabled = inboundEnable && outboundEnable;
1665 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1667 setEnv(inboundEnable);
1679 auto const outboundEnabled =
1681 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1696 cfg->VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
true;
1697 cfg->VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS = 6;
1700 , network_(env_.app())
1709 testInitialRound(log);
1710 testPeerUnsquelchedTooSoon(log);
1711 testPeerUnsquelched(log);
1713 testSquelchedPeerDisconnects(log);
1714 testSelectedPeerDisconnects(log);
1715 testSelectedPeerStopsRelaying(log);
1716 testInternalHashRouter(log);
1717 testRandomSquelch(log);
1719 testBaseSquelchReady(log);
1728 doTest(
"Random Test", log, [&](
bool log) { random(log); });
1739BEAST_DEFINE_TESTSUITE(reduce_relay, overlay,
ripple);
1740BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, overlay,
ripple);
T back_inserter(T... args)
A version-independent IP address and port combination.
A generic endpoint for log messages.
log_os< char > log
Logging output stream.
virtual Config & config()=0
bool VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
std::size_t VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS
Manages partitions for logging.
beast::Journal journal(std::string const &name)
Represents a peer connection in the overlay.
std::uint32_t id_t
Uniquely identifies a peer.
std::uint8_t const * data() const noexcept
std::size_t size() const noexcept
An immutable linear range of bytes.
Slot is associated with a specific validator via validator's public key.
Slots is a container for validator's Slot and handles Slot update when a message is received from a v...
void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, id_t id, protocol::MessageType type)
Calls Slot::update of Slot associated with the validator, with a noop callback.
Maintains squelching of relaying messages from validators.
Simulate link from a validator to a peer directly connected to the server.
void send(MessageSPtr const &m, SquelchCB f)
Link(Validator &validator, PeerSPtr peer, Latency const &latency={milliseconds(5), milliseconds(15)})
static void reset() noexcept
std::chrono::duration< std::uint32_t, period > duration
static void advance(duration d) noexcept
static duration randDuration(milliseconds min, milliseconds max)
std::chrono::time_point< ManualClock > time_point
static void randAdvance(milliseconds min, milliseconds max)
static bool const is_steady
static time_point now() noexcept
Validator & validator(std::uint16_t v)
std::vector< Validator > validators_
bool isSelected(Peer::id_t id)
Is peer in Selected state in any of the slots.
Network(Application &app)
bool allCounting(Peer::id_t peer)
Check if there are peers to unsquelch - peer is in Selected state in any of the slots and there are p...
void propagate(LinkIterCB link, std::uint16_t nValidators=MAX_VALIDATORS, std::uint32_t nMessages=MAX_MESSAGES, bool purge=true, bool resetClock=true)
void for_rand(std::uint32_t min, std::uint32_t max, std::function< void(std::uint32_t)> f)
void onDisconnectPeer(Peer::id_t peer)
void enableLink(std::uint16_t validatorId, Peer::id_t peer, bool enable)
reduce_relay::Slots< ManualClock > slots_
std::uint16_t getNumPeers() const
OverlaySim(Application &app)
std::uint16_t inState(PublicKey const &validator, reduce_relay::PeerState state)
void unsquelch(PublicKey const &validator, Peer::id_t id) const override
Unsquelch handler.
PeerSPtr addPeer(bool useCache=true)
void deletePeer(id_t id, UnsquelchCB f) override
std::optional< Peer::id_t > deleteLastPeer()
void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, Peer::id_t id, SquelchCB f, protocol::MessageType type=protocol::mtVALIDATION) override
void deleteIdlePeers(UnsquelchCB f) override
void squelch(PublicKey const &validator, Peer::id_t id, std::uint32_t squelchDuration) const override
Squelch handler.
bool isSelected(PublicKey const &validator, Peer::id_t peer)
void deletePeer(Peer::id_t id, bool useCache=true)
bool isCountingState(PublicKey const &validator)
std::set< id_t > getSelected(PublicKey const &validator)
std::unordered_map< id_t, std::tuple< reduce_relay::PeerState, std::uint16_t, std::uint32_t, std::uint32_t > > getPeers(PublicKey const &validator)
id_t getSelectedPeer(PublicKey const &validator)
Simulate server's OverlayImpl.
virtual void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, Peer::id_t id, SquelchCB f, protocol::MessageType type=protocol::mtVALIDATION)=0
virtual ~Overlay()=default
virtual void deletePeer(Peer::id_t, UnsquelchCB)=0
virtual void deleteIdlePeers(UnsquelchCB)=0
Simulate two entities - peer directly connected to the server (via squelch in PeerSim) and PeerImp (v...
virtual void onMessage(protocol::TMSquelch const &squelch)=0
void removeTxQueue(uint256 const &) override
Remove hash from the transactions' hashes queue.
std::optional< std::size_t > publisherListSequence(PublicKey const &) const override
void send(protocol::TMSquelch const &squelch)
bool txReduceRelayEnabled() const override
void addTxQueue(uint256 const &) override
Aggregate transaction's hash.
uint256 const & getClosedLedgerHash() const override
bool hasRange(std::uint32_t uMin, std::uint32_t uMax) override
virtual void onMessage(MessageSPtr const &m, SquelchCB f)=0
Json::Value json() override
void send(std::shared_ptr< Message > const &m) override
bool compressionEnabled() const override
beast::IP::Endpoint getRemoteAddress() const override
bool cluster() const override
Returns true if this connection is a member of the cluster.
void setPublisherListSequence(PublicKey const &, std::size_t const) override
int getScore(bool) const override
void charge(Resource::Charge const &fee, std::string const &context={}) override
Adjust this peer's load balance based on the type of load imposed.
bool supportsFeature(ProtocolFeature f) const override
PublicKey const & getNodePublic() const override
void cycleStatus() override
bool isHighLatency() const override
bool hasTxSet(uint256 const &hash) const override
bool hasLedger(uint256 const &hash, std::uint32_t seq) const override
void sendTxQueue() override
Send aggregated transactions' hashes.
void ledgerRange(std::uint32_t &minSeq, std::uint32_t &maxSeq) const override
PeerSim(Overlay &overlay, beast::Journal journal)
virtual void onMessage(protocol::TMSquelch const &squelch) override
Remote Peer (Directly connected Peer)
void onMessage(MessageSPtr const &m, SquelchCB f) override
Local Peer (PeerImp)
reduce_relay::Squelch< ManualClock > squelch_
std::string const & fingerprint() const override
static std::uint16_t sid_
void addPeer(PeerSPtr peer)
Validator(Validator &&)=default
void send(SquelchCB f)
Send to all peers.
Validator & operator=(Validator &&)=default
void linkDown(Peer::id_t id)
void for_links(std::vector< Peer::id_t > peers, LinkIterCB f)
void deletePeer(Peer::id_t id)
void for_links(LinkIterCB f, bool simulateSlow=false)
Validator(Validator const &)=default
void send(std::vector< Peer::id_t > peers, SquelchCB f)
Send to specific peers.
void linkUp(Peer::id_t id)
Validator & operator=(Validator const &)=default
A transaction testing environment.
void run() override
Runs the suite.
void testRandom(bool log)
void testSquelchedPeerDisconnects(bool log)
Squelched peer disconnects.
void testNewPeer(bool log)
Receiving a message from new peer should change the slot's state to Counting.
void random(bool log)
Randomly brings the link between a validator and a peer down.
bool checkCounting(PublicKey const &validator, bool isCountingState)
bool propagateAndSquelch(bool log, bool purge=true, bool resetClock=true)
Propagate enough messages to generate one squelch event.
bool propagateNoSquelch(bool log, std::uint16_t nMessages, bool countingState, bool purge=true, bool resetClock=true)
Send fewer message so that squelch event is not generated.
Peer::id_t sendSquelch(PublicKey const &validator, PeerWPtr const &peerPtr, std::optional< std::uint32_t > duration)
Send squelch (if duration is set) or unsquelch (if duration not set)
void testPeerUnsquelched(bool log)
Receiving message from squelched peer should change the slot's state to Counting.
void testHandshake(bool log)
void testInternalHashRouter(bool log)
void testInitialRound(bool log)
Initial counting round: three peers receive message "faster" then others.
void testSelectedPeerStopsRelaying(bool log)
Selected peer stops relaying.
void run() override
Runs the suite.
void testConfig(bool log)
void testPeerUnsquelchedTooSoon(bool log)
Receiving message from squelched peer too soon should not change the slot's state to Counting.
void testRandomSquelch(bool l)
void testSelectedPeerDisconnects(bool log)
Selected peer disconnects.
void printPeers(std::string const &msg, std::uint16_t validator=0)
void doTest(std::string const &msg, bool log, std::function< void(bool)> f)
void testBaseSquelchReady(bool log)
boost::asio::ip::address Address
static constexpr auto IDLED
static constexpr uint16_t MAX_MESSAGE_THRESHOLD
static constexpr auto WAIT_ON_BOOTUP
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
std::shared_ptr< Message > MessageSPtr
static constexpr std::uint32_t MAX_PEERS
static constexpr std::uint32_t MAX_VALIDATORS
static constexpr std::uint32_t MAX_MESSAGES
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
http_response_type makeResponse(bool crawlPublic, http_request_type const &req, beast::IP::Address public_ip, beast::IP::Address remote_ip, uint256 const &sharedValue, std::optional< std::uint32_t > networkID, ProtocolVersion protocol, Application &app)
Make http response.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
int run(int argc, char **argv)
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
bool peerFeatureEnabled(headers const &request, std::string const &feature, std::string value, bool config)
Check if a feature should be enabled for a peer.
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
constexpr Number squelch(Number const &x, Number const &limit) noexcept
static constexpr char FEATURE_VPRR[]
Set the sequence number on a JTx.
std::uint32_t handledCnt_
time_point< ManualClock > time_
std::optional< PublicKey > key_
void squelch(PublicKey const &, Peer::id_t, std::uint32_t duration) const override
Squelch handler.
void unsquelch(PublicKey const &, Peer::id_t) const override
Unsquelch handler.