19#include <test/jtx/Env.h>
20#include <xrpld/overlay/Message.h>
21#include <xrpld/overlay/Peer.h>
22#include <xrpld/overlay/Slot.h>
23#include <xrpld/overlay/detail/Handshake.h>
24#include <xrpl/basics/random.h>
25#include <xrpl/beast/unit_test.h>
26#include <xrpl/protocol/SecretKey.h>
27#include <xrpl/protocol/messages.h>
29#include <boost/thread.hpp>
245 protocol::MessageType type = protocol::mtVALIDATION) = 0;
279 auto peer = std::dynamic_pointer_cast<PeerPartial>(sp);
280 peer->onMessage(m, f);
322 protocol::TMValidation v;
323 v.set_validation(
"validation");
324 message_ = std::make_shared<Message>(v, protocol::mtVALIDATION,
pkey_);
377 for (
auto id : peers)
433 it->second->up(
true);
441 it->second->up(
false);
533 return res ? *res : 0;
542 protocol::MessageType type = protocol::mtVALIDATION)
override
552 slots_.deletePeer(
id,
true);
569 peer = std::make_shared<PeerSim>(*
this,
logs_.
journal(
"Squelch"));
611 for (
auto& [
id, _] :
peers_)
639 return selected.find(peer) != selected.end();
646 assert(selected.size());
647 return *selected.begin();
770 return v.id() == validatorId;
791 squelch.clear_validatorpubkey();
805 auto size = max - min;
821 bool resetClock =
true)
832 for (
int m = 0; m < nMessages; ++m)
865 for (
auto& [_, v] : peers)
868 if (std::get<reduce_relay::PeerState>(v) ==
893 for (
auto& [k, v] : peers)
894 std::cout << k <<
":" << (int)std::get<reduce_relay::PeerState>(v)
912 auto sp = peerPtr.
lock();
914 std::dynamic_pointer_cast<PeerSim>(sp)->send(
squelch);
952 bool squelched =
false;
969 str <<
" selected: ";
970 for (
auto s : selected)
974 << (double)reduce_relay::epoch<milliseconds>(now)
977 <<
" random, squelched, validator: " <<
validator.id()
982 countingState ==
false &&
991 events[event].cnt_++;
992 events[event].validator_ =
validator.id();
994 events[event].peer_ = link.
peerId();
996 events[event].time_ = now;
1001 events[event].isSelected_ =
1006 events[event].isSelected_ =
1024 if (event.isSelected_)
1025 sendSquelch(v, peerPtr, {});
1026 event.handled_ =
true;
1034 (
event.isSelected_ ==
false && !
event.handled_) ||
1035 (event.isSelected_ ==
true &&
1036 (event.handled_ || allCounting));
1037 BEAST_EXPECT(handled);
1039 event.isSelected_ =
false;
1040 event.handledCnt_ += handled;
1041 event.handled_ =
false;
1057 bool mustHandle =
false;
1058 if (event.state_ ==
State::On && BEAST_EXPECT(event.key_))
1063 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1064 std::get<3>(peers[event.peer_]);
1065 mustHandle =
event.isSelected_ &&
1070 peers.find(event.peer_) != peers.end();
1074 event.handled_ =
true;
1075 if (mustHandle && v == event.key_)
1077 event.state_ = State::WaitReset;
1078 sendSquelch(validator, ptr, {});
1083 (!event.handled_ && !mustHandle);
1084 BEAST_EXPECT(handled);
1092 BEAST_EXPECT(handled);
1094 event.isSelected_ =
false;
1095 event.handledCnt_ += handled;
1096 event.handled_ =
false;
1101 auto&
down = events[EventType::LinkDown];
1102 auto& disconnected = events[EventType::PeerDisconnected];
1104 BEAST_EXPECT(
down.handledCnt_ >=
down.cnt_ - 1);
1106 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1110 <<
" peer disconnect count: " << disconnected.cnt_ <<
"/"
1111 << disconnected.handledCnt_;
1117 auto countingState = network_.overlay().isCountingState(
validator);
1118 BEAST_EXPECT(countingState == isCountingState);
1119 return countingState == isCountingState;
1137 doTest(
"Initial Round", log, [
this](
bool log) {
1138 BEAST_EXPECT(propagateAndSquelch(log));
1148 doTest(
"Peer Unsquelched Too Soon", log, [
this](
bool log) {
1149 BEAST_EXPECT(propagateNoSquelch(log, 1,
false,
false,
false));
1159 ManualClock::advance(
seconds(601));
1160 doTest(
"Peer Unsquelched", log, [
this](
bool log) {
1161 BEAST_EXPECT(propagateNoSquelch(log, 2,
true,
true,
false));
1179 sendSquelch(key, peerPtr,
duration);
1193 auto selected = network_.overlay().getSelected(network_.validator(0));
1195 BEAST_EXPECT(n == 1);
1196 auto res = checkCounting(network_.validator(0),
false);
1198 return n == 1 && res;
1208 bool resetClock =
true)
1210 bool squelched =
false;
1219 BEAST_EXPECT(
false);
1226 auto res = checkCounting(network_.validator(0), countingState);
1227 return !squelched && res;
1236 doTest(
"New Peer", log, [
this](
bool log) {
1237 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1239 BEAST_EXPECT(propagateNoSquelch(log, 1,
true,
false,
false));
1248 doTest(
"Selected Peer Disconnects", log, [
this](
bool log) {
1249 ManualClock::advance(
seconds(601));
1250 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1251 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1253 network_.overlay().deletePeer(
1259 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1268 doTest(
"Selected Peer Stops Relaying", log, [
this](
bool log) {
1269 ManualClock::advance(
seconds(601));
1270 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1273 network_.overlay().deleteIdlePeers(
1277 auto peers = network_.overlay().getPeers(network_.validator(0));
1280 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1289 doTest(
"Squelched Peer Disconnects", log, [
this](
bool log) {
1290 ManualClock::advance(
seconds(601));
1291 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1292 auto peers = network_.overlay().getPeers(network_.validator(0));
1293 auto it =
std::find_if(peers.begin(), peers.end(), [&](
auto it) {
1294 return std::get<reduce_relay::PeerState>(it.second) ==
1295 reduce_relay::PeerState::Squelched;
1297 assert(it != peers.end());
1299 network_.overlay().deletePeer(
1303 BEAST_EXPECT(unsquelched == 0);
1304 BEAST_EXPECT(checkCounting(network_.validator(0),
false));
1311 doTest(
"Config Test", log, [&](
bool log) {
1326 toLoad = (R
"rippleConfig(
1338 toLoad = R
"rippleConfig(
1353 doTest(
"Duplicate Message", log, [&](
bool log) {
1357 for (
int i = 0; i < nMessages; i++)
1360 network_.overlay().updateSlotAndSquelch(
1362 network_.validator(0),
1366 auto peers = network_.overlay().getPeers(network_.validator(0));
1369 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1372 network_.overlay().updateSlotAndSquelch(
1374 network_.validator(0),
1378 peers = network_.overlay().getPeers(network_.validator(0));
1379 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1382 network_.overlay().updateSlotAndSquelch(
1384 network_.validator(0),
1387 peers = network_.overlay().getPeers(network_.validator(0));
1389 BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
1415 doTest(
"Random Squelch", l, [&](
bool l) {
1419 auto run = [&](
int npeers) {
1422 env_.app().logs(), handler);
1430 for (
int peer = 0; peer < npeers; peer++)
1440 protocol::MessageType::mtVALIDATION);
1444 ManualClock::advance(
hours(1));
1447 using namespace reduce_relay;
1452 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1453 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1456 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1457 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1466 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1467 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1469 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1471 "warning: squelch duration is low",
1479 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1480 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1481 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1483 "warning: squelch duration is low",
1494 doTest(
"Handshake", log, [&](
bool log) {
1495 auto setEnv = [&](
bool enable) {
1498 str <<
"[reduce_relay]\n"
1499 <<
"vp_enable=" << enable <<
"\n"
1500 <<
"vp_squelch=" << enable <<
"\n"
1501 <<
"[compression]\n"
1504 env_.app().config().VP_REDUCE_RELAY_ENABLE =
1506 env_.app().config().VP_REDUCE_RELAY_SQUELCH =
1510 auto handshake = [&](
int outboundEnable,
int inboundEnable) {
1512 boost::asio::ip::address::from_string(
"172.1.1.100");
1514 setEnv(outboundEnable);
1517 env_.app().config().COMPRESSION,
1519 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1520 env_.app().config().VP_REDUCE_RELAY_ENABLE);
1522 http_request.version(request.version());
1523 http_request.base() = request.base();
1526 auto const peerEnabled = inboundEnable && outboundEnable;
1531 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1533 setEnv(inboundEnable);
1545 auto const outboundEnabled =
1547 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1569 testInitialRound(log);
1570 testPeerUnsquelchedTooSoon(log);
1571 testPeerUnsquelched(log);
1573 testSquelchedPeerDisconnects(log);
1574 testSelectedPeerDisconnects(log);
1575 testSelectedPeerStopsRelaying(log);
1576 testInternalHashRouter(log);
1577 testRandomSquelch(log);
1587 doTest(
"Random Test", log, [&](
bool log) { random(log); });
1598BEAST_DEFINE_TESTSUITE(reduce_relay, ripple_data,
ripple);
1599BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, ripple_data,
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.
bool VP_REDUCE_RELAY_ENABLE
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
bool VP_REDUCE_RELAY_SQUELCH
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.
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)
static const bool is_steady
std::chrono::time_point< ManualClock > time_point
static void randAdvance(milliseconds min, milliseconds max)
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
std::optional< std::size_t > publisherListSequence(PublicKey const &) const override
void send(protocol::TMSquelch const &squelch)
bool txReduceRelayEnabled() const override
void addTxQueue(const uint256 &) override
Aggregate transaction's hash.
uint256 const & getClosedLedgerHash() const override
void charge(Resource::Charge const &fee) override
Adjust this peer's load balance based on the type of load imposed.
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
bool supportsFeature(ProtocolFeature f) const override
PublicKey const & getNodePublic() const override
void removeTxQueue(const uint256 &) override
Remove hash from the transactions' hashes queue.
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 printPeers(const std::string &msg, std::uint16_t validator=0)
void testInitialRound(bool log)
Initial counting round: three peers receive message "faster" then others.
void doTest(const std::string &msg, bool log, std::function< void(bool)> f)
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.
boost::asio::ip::address Address
static constexpr uint16_t MAX_SELECTED_PEERS
static constexpr auto IDLED
static constexpr uint16_t MAX_MESSAGE_THRESHOLD
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
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.