21#include <test/jtx/Env.h>
23#include <xrpld/overlay/Message.h>
24#include <xrpld/overlay/Peer.h>
25#include <xrpld/overlay/Slot.h>
26#include <xrpld/overlay/Squelch.h>
27#include <xrpld/overlay/detail/Handshake.h>
29#include <xrpl/basics/random.h>
30#include <xrpl/beast/unit_test.h>
31#include <xrpl/protocol/SecretKey.h>
32#include <xrpl/protocol/messages.h>
34#include <boost/thread.hpp>
253 protocol::MessageType type = protocol::mtVALIDATION) = 0;
288 peer->onMessage(m, f);
330 protocol::TMValidation v;
331 v.set_validation(
"validation");
385 for (
auto id : peers)
441 it->second->up(
true);
449 it->second->up(
false);
524 :
slots_(app.logs(), *this, app.config()),
logs_(app.logs())
542 return res ? *res : 0;
551 protocol::MessageType type = protocol::mtVALIDATION)
override
561 slots_.deletePeer(
id,
true);
620 for (
auto& [
id, _] :
peers_)
648 return selected.find(peer) != selected.end();
655 assert(selected.size());
656 return *selected.begin();
779 return v.id() == validatorId;
800 squelch.clear_validatorpubkey();
814 auto size = max - min;
830 bool resetClock =
true)
841 for (
int m = 0; m < nMessages; ++m)
874 for (
auto& [_, v] : peers)
903 for (
auto& [k, v] : peers)
922 auto sp = peerPtr.
lock();
962 bool squelched =
false;
979 str <<
" selected: ";
980 for (
auto s : selected)
984 << (double)reduce_relay::epoch<milliseconds>(now)
987 <<
" random, squelched, validator: " <<
validator.id()
992 countingState ==
false &&
1004 events[event].cnt_++;
1005 events[event].validator_ =
validator.id();
1007 events[event].peer_ = link.
peerId();
1009 events[event].time_ = now;
1014 events[event].isSelected_ =
1019 events[event].isSelected_ =
1037 if (event.isSelected_)
1038 sendSquelch(v, peerPtr, {});
1039 event.handled_ =
true;
1047 (
event.isSelected_ ==
false && !
event.handled_) ||
1048 (event.isSelected_ ==
true &&
1049 (event.handled_ || allCounting));
1050 BEAST_EXPECT(handled);
1052 event.isSelected_ =
false;
1053 event.handledCnt_ += handled;
1054 event.handled_ =
false;
1070 bool mustHandle =
false;
1071 if (event.state_ ==
State::On && BEAST_EXPECT(event.key_))
1076 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1078 mustHandle =
event.isSelected_ &&
1083 peers.find(event.peer_) != peers.end();
1087 event.handled_ =
true;
1088 if (mustHandle && v == event.key_)
1090 event.state_ = State::WaitReset;
1091 sendSquelch(validator, ptr, {});
1096 (!event.handled_ && !mustHandle);
1097 BEAST_EXPECT(handled);
1105 BEAST_EXPECT(handled);
1107 event.isSelected_ =
false;
1108 event.handledCnt_ += handled;
1109 event.handled_ =
false;
1114 auto&
down = events[EventType::LinkDown];
1115 auto& disconnected = events[EventType::PeerDisconnected];
1117 BEAST_EXPECT(
down.handledCnt_ >=
down.cnt_ - 1);
1119 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1123 <<
" peer disconnect count: " << disconnected.cnt_ <<
"/"
1124 << disconnected.handledCnt_;
1130 auto countingState = network_.overlay().isCountingState(
validator);
1131 BEAST_EXPECT(countingState == isCountingState);
1132 return countingState == isCountingState;
1150 doTest(
"Initial Round", log, [
this](
bool log) {
1151 BEAST_EXPECT(propagateAndSquelch(log));
1161 doTest(
"Peer Unsquelched Too Soon", log, [
this](
bool log) {
1162 BEAST_EXPECT(propagateNoSquelch(log, 1,
false,
false,
false));
1172 ManualClock::advance(
seconds(601));
1173 doTest(
"Peer Unsquelched", log, [
this](
bool log) {
1174 BEAST_EXPECT(propagateNoSquelch(log, 2,
true,
true,
false));
1192 sendSquelch(key, peerPtr,
duration);
1201 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1209 auto selected = network_.overlay().getSelected(network_.validator(0));
1212 env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1213 BEAST_EXPECT(n == 1);
1214 auto res = checkCounting(network_.validator(0),
false);
1216 return n == 1 && res;
1226 bool resetClock =
true)
1228 bool squelched =
false;
1237 BEAST_EXPECT(
false);
1244 auto res = checkCounting(network_.validator(0), countingState);
1245 return !squelched && res;
1254 doTest(
"New Peer", log, [
this](
bool log) {
1255 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1257 BEAST_EXPECT(propagateNoSquelch(log, 1,
true,
false,
false));
1266 doTest(
"Selected Peer Disconnects", log, [
this](
bool log) {
1267 ManualClock::advance(
seconds(601));
1268 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1269 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1271 network_.overlay().deletePeer(
1280 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1281 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1290 doTest(
"Selected Peer Stops Relaying", log, [
this](
bool log) {
1291 ManualClock::advance(
seconds(601));
1292 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1295 network_.overlay().deleteIdlePeers(
1299 auto peers = network_.overlay().getPeers(network_.validator(0));
1305 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1306 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1315 doTest(
"Squelched Peer Disconnects", log, [
this](
bool log) {
1316 ManualClock::advance(
seconds(601));
1317 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1318 auto peers = network_.overlay().getPeers(network_.validator(0));
1319 auto it =
std::find_if(peers.begin(), peers.end(), [&](
auto it) {
1320 return std::get<reduce_relay::PeerState>(it.second) ==
1321 reduce_relay::PeerState::Squelched;
1323 assert(it != peers.end());
1325 network_.overlay().deletePeer(
1329 BEAST_EXPECT(unsquelched == 0);
1330 BEAST_EXPECT(checkCounting(network_.validator(0),
false));
1337 doTest(
"Test Config - squelch enabled (legacy)", log, [&](
bool log) {
1349 doTest(
"Test Config - squelch disabled (legacy)", log, [&](
bool log) {
1362 toLoad = R
"rippleConfig(
1370 doTest(
"Test Config - squelch enabled", log, [&](
bool log) {
1375vp_base_squelch_enable=1
1382 doTest(
"Test Config - squelch disabled", log, [&](
bool log) {
1387vp_base_squelch_enable=0
1394 doTest(
"Test Config - legacy and new", log, [&](
bool log) {
1399vp_base_squelch_enable=0
1404 auto const expectedError =
1405 "Invalid reduce_relay"
1406 " cannot specify both vp_base_squelch_enable and vp_enable "
1408 "vp_enable was deprecated and replaced by "
1409 "vp_base_squelch_enable";
1420 BEAST_EXPECT(error == expectedError);
1423 doTest(
"Test Config - max selected peers", log, [&](
bool log) {
1435 toLoad = R"rippleConfig(
1437vp_base_squelch_max_selected_peers=6
1445 toLoad = R"rippleConfig(
1447vp_base_squelch_max_selected_peers=2
1451 auto const expectedError =
1452 "Invalid reduce_relay"
1453 " vp_base_squelch_max_selected_peers must be "
1454 "greater than or equal to 3";
1464 BEAST_EXPECT(error == expectedError);
1471 doTest(
"BaseSquelchReady", log, [&](
bool log) {
1472 ManualClock::reset();
1473 auto createSlots = [&](
bool baseSquelchEnabled)
1475 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
1478 env_.app().logs(), network_.overlay(), env_.app().config());
1481 BEAST_EXPECT(!createSlots(
false).baseSquelchReady());
1485 BEAST_EXPECT(!createSlots(
true).baseSquelchReady());
1490 BEAST_EXPECT(createSlots(
true).baseSquelchReady());
1494 BEAST_EXPECT(!createSlots(
false).baseSquelchReady());
1501 doTest(
"Duplicate Message", log, [&](
bool log) {
1505 for (
int i = 0; i < nMessages; i++)
1508 network_.overlay().updateSlotAndSquelch(
1510 network_.validator(0),
1514 auto peers = network_.overlay().getPeers(network_.validator(0));
1517 BEAST_EXPECT(
std::get<1>(peers[0]) == (nMessages - 1));
1520 network_.overlay().updateSlotAndSquelch(
1522 network_.validator(0),
1526 peers = network_.overlay().getPeers(network_.validator(0));
1527 BEAST_EXPECT(
std::get<1>(peers[0]) == (nMessages - 1));
1530 network_.overlay().updateSlotAndSquelch(
1532 network_.validator(0),
1535 peers = network_.overlay().getPeers(network_.validator(0));
1563 doTest(
"Random Squelch", l, [&](
bool l) {
1567 auto run = [&](
int npeers) {
1570 env_.app().logs(), handler, env_.app().config());
1578 for (
int peer = 0; peer < npeers; peer++)
1588 protocol::MessageType::mtVALIDATION);
1592 ManualClock::advance(
hours(1));
1595 using namespace reduce_relay;
1600 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1601 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1604 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1605 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1614 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1615 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1617 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1619 "warning: squelch duration is low",
1627 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1628 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1629 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1631 "warning: squelch duration is low",
1642 doTest(
"Handshake", log, [&](
bool log) {
1643 auto setEnv = [&](
bool enable) {
1646 str <<
"[reduce_relay]\n"
1647 <<
"vp_enable=" << enable <<
"\n"
1648 <<
"[compression]\n"
1651 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
1656 auto handshake = [&](
int outboundEnable,
int inboundEnable) {
1658 boost::asio::ip::make_address(
"172.1.1.100");
1660 setEnv(outboundEnable);
1663 env_.app().config().COMPRESSION,
1665 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1666 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE);
1668 http_request.version(request.version());
1669 http_request.base() = request.base();
1672 auto const peerEnabled = inboundEnable && outboundEnable;
1677 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1679 setEnv(inboundEnable);
1691 auto const outboundEnabled =
1693 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1708 cfg->VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
true;
1709 cfg->VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS = 6;
1712 , network_(env_.app())
1721 testInitialRound(log);
1722 testPeerUnsquelchedTooSoon(log);
1723 testPeerUnsquelched(log);
1725 testSquelchedPeerDisconnects(log);
1726 testSelectedPeerDisconnects(log);
1727 testSelectedPeerStopsRelaying(log);
1728 testInternalHashRouter(log);
1729 testRandomSquelch(log);
1731 testBaseSquelchReady(log);
1740 doTest(
"Random Test", log, [&](
bool log) { random(log); });
1751BEAST_DEFINE_TESTSUITE(reduce_relay, overlay,
ripple);
1752BEAST_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_
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.