20#include <test/jtx/Env.h>
22#include <xrpld/overlay/Message.h>
23#include <xrpld/overlay/Peer.h>
24#include <xrpld/overlay/Slot.h>
25#include <xrpld/overlay/Squelch.h>
26#include <xrpld/overlay/detail/Handshake.h>
28#include <xrpl/basics/random.h>
29#include <xrpl/beast/unit_test.h>
30#include <xrpl/protocol/SecretKey.h>
31#include <xrpl/protocol/messages.h>
33#include <boost/thread.hpp>
250 protocol::MessageType type = protocol::mtVALIDATION) = 0;
284 auto peer = std::dynamic_pointer_cast<PeerPartial>(sp);
285 peer->onMessage(m, f);
327 protocol::TMValidation v;
328 v.set_validation(
"validation");
329 message_ = std::make_shared<Message>(v, protocol::mtVALIDATION,
pkey_);
382 for (
auto id : peers)
438 it->second->up(
true);
446 it->second->up(
false);
538 return res ? *res : 0;
547 protocol::MessageType type = protocol::mtVALIDATION)
override
557 slots_.deletePeer(
id,
true);
574 peer = std::make_shared<PeerSim>(*
this,
logs_.
journal(
"Squelch"));
616 for (
auto& [
id, _] :
peers_)
644 return selected.find(peer) != selected.end();
651 assert(selected.size());
652 return *selected.begin();
775 return v.id() == validatorId;
796 squelch.clear_validatorpubkey();
810 auto size = max - min;
826 bool resetClock =
true)
837 for (
int m = 0; m < nMessages; ++m)
870 for (
auto& [_, v] : peers)
873 if (std::get<reduce_relay::PeerState>(v) ==
898 for (
auto& [k, v] : peers)
899 std::cout << k <<
":" << (int)std::get<reduce_relay::PeerState>(v)
917 auto sp = peerPtr.
lock();
919 std::dynamic_pointer_cast<PeerSim>(sp)->send(
squelch);
957 bool squelched =
false;
974 str <<
" selected: ";
975 for (
auto s : selected)
979 << (double)reduce_relay::epoch<milliseconds>(now)
982 <<
" random, squelched, validator: " <<
validator.id()
987 countingState ==
false &&
996 events[event].cnt_++;
997 events[event].validator_ =
validator.id();
999 events[event].peer_ = link.
peerId();
1001 events[event].time_ = now;
1006 events[event].isSelected_ =
1011 events[event].isSelected_ =
1029 if (event.isSelected_)
1030 sendSquelch(v, peerPtr, {});
1031 event.handled_ =
true;
1039 (
event.isSelected_ ==
false && !
event.handled_) ||
1040 (event.isSelected_ ==
true &&
1041 (event.handled_ || allCounting));
1042 BEAST_EXPECT(handled);
1044 event.isSelected_ =
false;
1045 event.handledCnt_ += handled;
1046 event.handled_ =
false;
1062 bool mustHandle =
false;
1063 if (event.state_ ==
State::On && BEAST_EXPECT(event.key_))
1068 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1069 std::get<3>(peers[event.peer_]);
1070 mustHandle =
event.isSelected_ &&
1075 peers.find(event.peer_) != peers.end();
1079 event.handled_ =
true;
1080 if (mustHandle && v == event.key_)
1082 event.state_ = State::WaitReset;
1083 sendSquelch(validator, ptr, {});
1088 (!event.handled_ && !mustHandle);
1089 BEAST_EXPECT(handled);
1097 BEAST_EXPECT(handled);
1099 event.isSelected_ =
false;
1100 event.handledCnt_ += handled;
1101 event.handled_ =
false;
1106 auto&
down = events[EventType::LinkDown];
1107 auto& disconnected = events[EventType::PeerDisconnected];
1109 BEAST_EXPECT(
down.handledCnt_ >=
down.cnt_ - 1);
1111 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1115 <<
" peer disconnect count: " << disconnected.cnt_ <<
"/"
1116 << disconnected.handledCnt_;
1122 auto countingState = network_.overlay().isCountingState(
validator);
1123 BEAST_EXPECT(countingState == isCountingState);
1124 return countingState == isCountingState;
1142 doTest(
"Initial Round", log, [
this](
bool log) {
1143 BEAST_EXPECT(propagateAndSquelch(log));
1153 doTest(
"Peer Unsquelched Too Soon", log, [
this](
bool log) {
1154 BEAST_EXPECT(propagateNoSquelch(log, 1,
false,
false,
false));
1164 ManualClock::advance(
seconds(601));
1165 doTest(
"Peer Unsquelched", log, [
this](
bool log) {
1166 BEAST_EXPECT(propagateNoSquelch(log, 2,
true,
true,
false));
1184 sendSquelch(key, peerPtr,
duration);
1198 auto selected = network_.overlay().getSelected(network_.validator(0));
1200 BEAST_EXPECT(n == 1);
1201 auto res = checkCounting(network_.validator(0),
false);
1203 return n == 1 && res;
1213 bool resetClock =
true)
1215 bool squelched =
false;
1224 BEAST_EXPECT(
false);
1231 auto res = checkCounting(network_.validator(0), countingState);
1232 return !squelched && res;
1241 doTest(
"New Peer", log, [
this](
bool log) {
1242 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1244 BEAST_EXPECT(propagateNoSquelch(log, 1,
true,
false,
false));
1253 doTest(
"Selected Peer Disconnects", log, [
this](
bool log) {
1254 ManualClock::advance(
seconds(601));
1255 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1256 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1258 network_.overlay().deletePeer(
1264 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1273 doTest(
"Selected Peer Stops Relaying", log, [
this](
bool log) {
1274 ManualClock::advance(
seconds(601));
1275 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1278 network_.overlay().deleteIdlePeers(
1282 auto peers = network_.overlay().getPeers(network_.validator(0));
1285 BEAST_EXPECT(checkCounting(network_.validator(0),
true));
1294 doTest(
"Squelched Peer Disconnects", log, [
this](
bool log) {
1295 ManualClock::advance(
seconds(601));
1296 BEAST_EXPECT(propagateAndSquelch(log,
true,
false));
1297 auto peers = network_.overlay().getPeers(network_.validator(0));
1298 auto it =
std::find_if(peers.begin(), peers.end(), [&](
auto it) {
1299 return std::get<reduce_relay::PeerState>(it.second) ==
1300 reduce_relay::PeerState::Squelched;
1302 assert(it != peers.end());
1304 network_.overlay().deletePeer(
1308 BEAST_EXPECT(unsquelched == 0);
1309 BEAST_EXPECT(checkCounting(network_.validator(0),
false));
1316 doTest(
"Config Test", log, [&](
bool log) {
1331 toLoad = (R
"rippleConfig(
1343 toLoad = R
"rippleConfig(
1358 doTest(
"Duplicate Message", log, [&](
bool log) {
1362 for (
int i = 0; i < nMessages; i++)
1365 network_.overlay().updateSlotAndSquelch(
1367 network_.validator(0),
1371 auto peers = network_.overlay().getPeers(network_.validator(0));
1374 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1377 network_.overlay().updateSlotAndSquelch(
1379 network_.validator(0),
1383 peers = network_.overlay().getPeers(network_.validator(0));
1384 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1387 network_.overlay().updateSlotAndSquelch(
1389 network_.validator(0),
1392 peers = network_.overlay().getPeers(network_.validator(0));
1394 BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
1420 doTest(
"Random Squelch", l, [&](
bool l) {
1424 auto run = [&](
int npeers) {
1427 env_.app().logs(), handler);
1435 for (
int peer = 0; peer < npeers; peer++)
1445 protocol::MessageType::mtVALIDATION);
1449 ManualClock::advance(
hours(1));
1452 using namespace reduce_relay;
1457 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1458 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1461 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1462 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1471 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1472 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1474 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1476 "warning: squelch duration is low",
1484 handler.
maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1485 handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1486 if (handler.
maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1488 "warning: squelch duration is low",
1499 doTest(
"Handshake", log, [&](
bool log) {
1500 auto setEnv = [&](
bool enable) {
1503 str <<
"[reduce_relay]\n"
1504 <<
"vp_enable=" << enable <<
"\n"
1505 <<
"vp_squelch=" << enable <<
"\n"
1506 <<
"[compression]\n"
1509 env_.app().config().VP_REDUCE_RELAY_ENABLE =
1511 env_.app().config().VP_REDUCE_RELAY_SQUELCH =
1515 auto handshake = [&](
int outboundEnable,
int inboundEnable) {
1517 boost::asio::ip::address::from_string(
"172.1.1.100");
1519 setEnv(outboundEnable);
1522 env_.app().config().COMPRESSION,
1524 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1525 env_.app().config().VP_REDUCE_RELAY_ENABLE);
1527 http_request.version(request.version());
1528 http_request.base() = request.base();
1531 auto const peerEnabled = inboundEnable && outboundEnable;
1536 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1538 setEnv(inboundEnable);
1550 auto const outboundEnabled =
1552 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1574 testInitialRound(log);
1575 testPeerUnsquelchedTooSoon(log);
1576 testPeerUnsquelched(log);
1578 testSquelchedPeerDisconnects(log);
1579 testSelectedPeerDisconnects(log);
1580 testSelectedPeerStopsRelaying(log);
1581 testInternalHashRouter(log);
1582 testRandomSquelch(log);
1592 doTest(
"Random Test", log, [&](
bool log) { random(log); });
1603BEAST_DEFINE_TESTSUITE(reduce_relay, ripple_data,
ripple);
1604BEAST_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
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 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.