xrpld
Loading...
Searching...
No Matches
reduce_relay_test.cpp
1#include <test/jtx/Env.h>
2#include <test/jtx/envconfig.h>
3
4#include <xrpld/app/main/Application.h>
5#include <xrpld/overlay/Message.h>
6#include <xrpld/overlay/Peer.h>
7#include <xrpld/overlay/ReduceRelayCommon.h>
8#include <xrpld/overlay/Slot.h>
9#include <xrpld/overlay/Squelch.h>
10#include <xrpld/overlay/detail/Handshake.h>
11
12#include <xrpl/basics/base_uint.h>
13#include <xrpl/basics/random.h>
14#include <xrpl/beast/net/IPAddress.h>
15#include <xrpl/beast/net/IPEndpoint.h>
16#include <xrpl/beast/unit_test/suite.h>
17#include <xrpl/beast/utility/Journal.h>
18#include <xrpl/json/json_value.h>
19#include <xrpl/protocol/KeyType.h>
20#include <xrpl/protocol/PublicKey.h>
21#include <xrpl/protocol/SecretKey.h>
22
23#include <boost/asio/ip/address.hpp>
24
25#include <xrpl.pb.h>
26
27#include <algorithm>
28#include <cassert>
29#include <chrono>
30#include <cstddef>
31#include <cstdint>
32#include <functional>
33#include <iostream>
34#include <iterator>
35#include <memory>
36#include <numeric>
37#include <optional>
38#include <random>
39#include <ratio>
40#include <set>
41#include <sstream>
42#include <stdexcept>
43#include <string>
44#include <tuple>
45#include <unordered_map>
46#include <utility>
47#include <vector>
48
49namespace xrpl::test {
50
51using namespace std::chrono;
52
53class Link;
54
60using UnsquelchCB = std::function<void(PublicKey const&, PeerWPtr const&)>;
62
63static constexpr std::uint32_t kMaxPeers = 10;
64static constexpr std::uint32_t kMaxValidators = 10;
65static constexpr std::uint32_t kMaxMessages = 200000;
66
70class PeerPartial : public Peer
71{
72public:
76
78 ~PeerPartial() override = default;
79 virtual void
81 virtual void
82 onMessage(protocol::TMSquelch const& squelch) = 0;
83 void
84 send(protocol::TMSquelch const& squelch)
85 {
87 }
88
89 // dummy implementation
90 void
91 send(std::shared_ptr<Message> const& m) override
92 {
93 }
94 [[nodiscard]] beast::IP::Endpoint
95 getRemoteAddress() const override
96 {
97 return {};
98 }
99 void
100 charge(Resource::Charge const& fee, std::string const& context = {}) override
101 {
102 }
103 [[nodiscard]] bool
104 cluster() const override
105 {
106 return false;
107 }
108 [[nodiscard]] bool
109 isHighLatency() const override
110 {
111 return false;
112 }
113 [[nodiscard]] int
114 getScore(bool) const override
115 {
116 return 0;
117 }
118 [[nodiscard]] PublicKey const&
119 getNodePublic() const override
120 {
121 return nodePublicKey;
122 }
124 json() override
125 {
126 return {};
127 }
128 [[nodiscard]] bool
130 {
131 return false;
132 }
133 [[nodiscard]] std::optional<std::size_t>
134 publisherListSequence(PublicKey const&) const override
135 {
136 return {};
137 }
138 void
140 {
141 }
142 [[nodiscard]] uint256 const&
143 getClosedLedgerHash() const override
144 {
145 static uint256 const kHash{};
146 return kHash;
147 }
148 [[nodiscard]] bool
149 hasLedger(uint256 const& hash, std::uint32_t seq) const override
150 {
151 return false;
152 }
153 void
154 ledgerRange(std::uint32_t& minSeq, std::uint32_t& maxSeq) const override
155 {
156 }
157 [[nodiscard]] bool
158 hasTxSet(uint256 const& hash) const override
159 {
160 return false;
161 }
162 void
163 cycleStatus() override
164 {
165 }
166 bool
168 {
169 return false;
170 }
171 [[nodiscard]] bool
172 compressionEnabled() const override
173 {
174 return false;
175 }
176 [[nodiscard]] bool
177 txReduceRelayEnabled() const override
178 {
179 return false;
180 }
181 void
182 sendTxQueue() override
183 {
184 }
185 void
186 addTxQueue(uint256 const&) override
187 {
188 }
189 void
190 removeTxQueue(uint256 const&) override
191 {
192 }
193};
194
197{
198public:
199 using rep = uint64_t;
203 inline static bool const is_steady = false; // NOLINT(readability-identifier-naming)
204
205 static void
206 advance(duration d) noexcept
207 {
208 kNow += d;
209 }
210
211 static void
216
217 static void
218 reset() noexcept
219 {
220 kNow = time_point(seconds(0));
221 }
222
223 static time_point
224 now() noexcept
225 {
226 return kNow;
227 }
228
229 static duration
231 {
232 return duration(milliseconds(randInt(min.count(), max.count())));
233 }
234
235 explicit ManualClock() = default;
236
237private:
238 inline static time_point kNow = time_point(seconds(0));
239};
240
243{
244public:
245 Overlay() = default;
246 virtual ~Overlay() = default;
247
248 virtual void
250 uint256 const& key,
251 PublicKey const& validator,
252 Peer::id_t id,
253 SquelchCB f,
254 protocol::MessageType type = protocol::mtVALIDATION) = 0;
255
256 virtual void deleteIdlePeers(UnsquelchCB) = 0;
257
259};
260
261class Validator;
262
266class Link
267{
269
270public:
272 : validator_(validator), peer_(peer), latency_(std::move(latency))
273 {
274 auto sp = peer_.lock();
275 assert(sp);
276 }
277 ~Link() = default;
278 void
280 {
281 if (!up_)
282 return;
283 auto sp = peer_.lock();
284 assert(sp);
286 peer->onMessage(m, f);
287 }
288 Validator&
290 {
291 return validator_;
292 }
293 void
294 up(bool linkUp)
295 {
296 up_ = linkUp;
297 }
300 {
301 auto p = peer_.lock();
302 assert(p);
303 return p->id();
304 }
307 {
308 auto p = peer_.lock();
309 assert(p);
310 return p;
311 }
312
313private:
317 bool up_{true};
318};
319
322{
324
325public:
327 {
328 protocol::TMValidation v;
329 v.set_validation("validation");
330 message_ = std::make_shared<Message>(v, protocol::mtVALIDATION, pkey_);
331 id_ = sid++;
332 }
333 Validator(Validator const&) = default;
334 Validator(Validator&&) = default;
335 Validator&
336 operator=(Validator const&) = default;
337 Validator&
338 operator=(Validator&&) = default;
340 {
341 clear();
342 }
343
344 void
346 {
347 links_.clear();
348 }
349
350 static void
352 {
353 sid = 0;
354 }
355
356 PublicKey const&
358 {
359 return pkey_;
360 }
361
362 operator PublicKey() const
363 {
364 return pkey_;
365 }
366
367 void
369 {
370 links_.emplace(std::make_pair(peer->id(), std::make_shared<Link>(*this, peer)));
371 }
372
373 void
375 {
376 links_.erase(id);
377 }
378
379 void
381 {
382 for (auto id : peers)
383 {
384 assert(links_.contains(id));
385 f(*links_[id], message_);
386 }
387 }
388
389 void
390 forLinks(LinkIterCB f, bool simulateSlow = false)
391 {
393 std::ranges::transform(links_, std::back_inserter(v), [](auto& kv) { return kv.second; });
395 std::mt19937 g(d());
396 std::shuffle(v.begin(), v.end(), g);
397
398 for (auto& link : v)
399 {
400 f(*link, message_);
401 }
402 }
403
405 void
407 {
408 forLinks(peers, [&](Link& link, MessageSPtr m) { link.send(m, f); });
409 }
410
412 void
414 {
415 forLinks([&](Link& link, MessageSPtr m) { link.send(m, f); });
416 }
417
420 {
421 return message_;
422 }
423
424 [[nodiscard]] std::uint16_t
425 id() const
426 {
427 return id_;
428 }
429
430 void
432 {
433 auto it = links_.find(id);
434 assert(it != links_.end());
435 it->second->up(true);
436 }
437
438 void
440 {
441 auto it = links_.find(id);
442 assert(it != links_.end());
443 it->second->up(false);
444 }
445
446private:
450 inline static std::uint16_t sid = 0;
452};
453
454class PeerSim : public PeerPartial, public std::enable_shared_from_this<PeerSim>
455{
456public:
458 PeerSim(Overlay& overlay, beast::Journal journal) : overlay_(overlay), squelch_(journal)
459 {
460 id_ = sid++;
461 }
462
463 ~PeerSim() override = default;
464
465 id_t
466 id() const override
467 {
468 return id_;
469 }
470
471 std::string const&
472 fingerprint() const override
473 {
474 return fingerprint_;
475 }
476
477 static void
479 {
480 sid = 0;
481 }
482
484 void
485 onMessage(MessageSPtr const& m, SquelchCB f) override
486 {
487 auto validator = m->getValidatorKey();
488 assert(validator);
489 if (!squelch_.expireSquelch(*validator)) // NOLINT(bugprone-unchecked-optional-access)
490 return;
491
492 overlay_.updateSlotAndSquelch(
493 {}, *validator, id(), f); // NOLINT(bugprone-unchecked-optional-access)
494 }
495
497 void
498 onMessage(protocol::TMSquelch const& squelch) override
499 {
500 auto validator = squelch.validatorpubkey();
501 PublicKey const key(Slice(validator.data(), validator.size()));
502 if (squelch.squelch())
503 {
504 squelch_.addSquelch(key, std::chrono::seconds{squelch.squelchduration()});
505 }
506 else
507 {
508 squelch_.removeSquelch(key);
509 }
510 }
511
512private:
513 inline static id_t sid = 0;
518};
519
521{
523
524public:
527 OverlaySim(Application& app) : slots_(app, *this, app.config()), registry_(app)
528 {
529 }
530
531 ~OverlaySim() override = default;
532
533 void
535 {
536 peers_.clear();
538 slots_.deleteIdlePeers();
539 }
540
543 {
544 auto res = slots_.inState(validator, state);
545 return res ? *res : 0;
546 }
547
548 void
550 uint256 const& key,
551 PublicKey const& validator,
552 Peer::id_t id,
553 SquelchCB f,
554 protocol::MessageType type = protocol::mtVALIDATION) override
555 {
556 squelch_ = f;
557 slots_.updateSlotAndSquelch(key, validator, id, type);
558 }
559
560 void
562 {
563 unsquelch_ = f;
564 slots_.deletePeer(id, true);
565 }
566
567 void
569 {
570 unsquelch_ = f;
571 slots_.deleteIdlePeers();
572 }
573
575 addPeer(bool useCache = true)
576 {
577 PeerSPtr peer{};
578 Peer::id_t id = 0;
579 if (peersCache_.empty() || !useCache)
580 {
581 peer = std::make_shared<PeerSim>(*this, registry_.getJournal("Squelch"));
582 id = peer->id();
583 }
584 else
585 {
586 auto it = peersCache_.begin();
587 peer = it->second;
588 id = it->first;
589 peersCache_.erase(it);
590 }
591 peers_.emplace(std::make_pair(id, peer));
592 return peer;
593 }
594
595 void
596 deletePeer(Peer::id_t id, bool useCache = true)
597 {
598 auto it = peers_.find(id);
599 assert(it != peers_.end());
600 deletePeer(id, [&](PublicKey const&, PeerWPtr) {});
601 if (useCache)
602 peersCache_.emplace(std::make_pair(id, it->second));
603 peers_.erase(it);
604 }
605
606 void
608 {
609 while (!peers_.empty())
610 deletePeer(peers_.begin()->first);
611 while (!peersCache_.empty())
612 addPeer();
613 }
614
617 {
618 if (peers_.empty())
619 return {};
620
621 std::uint8_t maxId = 0;
622
623 for (auto& [id, _] : peers_)
624 {
625 (void)_;
626 maxId = std::max<unsigned int>(id, maxId);
627 }
628
629 deletePeer(maxId, false);
630
631 return maxId;
632 }
633
634 bool
639
642 {
643 return slots_.getSelected(validator);
644 }
645
646 bool
648 {
649 auto selected = slots_.getSelected(validator);
650 return selected.contains(peer);
651 }
652
653 id_t
655 {
656 auto selected = slots_.getSelected(validator);
657 assert(!selected.empty());
658 return *selected.begin();
659 }
660
662 id_t,
665 {
666 return slots_.getPeers(validator);
667 }
668
671 {
672 return peers_.size();
673 }
674
675private:
676 void
677 squelch(PublicKey const& validator, Peer::id_t id, std::uint32_t squelchDuration) const override
678 {
679 if (auto it = peers_.find(id); it != peers_.end())
680 squelch_(validator, it->second, squelchDuration);
681 }
682 void
683 unsquelch(PublicKey const& validator, Peer::id_t id) const override
684 {
685 if (auto it = peers_.find(id); it != peers_.end())
686 unsquelch_(validator, it->second);
687 }
694};
695
697{
698public:
700 {
701 init();
702 }
703
704 void
706 {
708 for (int p = 0; p < kMaxPeers; p++)
709 {
710 auto peer = overlay_.addPeer();
711 for (auto& v : validators_)
712 v.addPeer(peer);
713 }
714 }
715
716 ~Network() = default;
717
718 void
720 {
721 validators_.clear();
722 overlay_.clear();
725 init();
726 }
727
730 {
731 auto peer = overlay_.addPeer();
732 for (auto& v : validators_)
733 v.addPeer(peer);
734 return peer->id();
735 }
736
737 void
739 {
740 auto id = overlay_.deleteLastPeer();
741
742 if (!id)
743 return;
744
745 for (auto& validator : validators_)
746 validator.deletePeer(*id);
747 }
748
749 void
751 {
752 while (overlay_.getNumPeers() > kMaxPeers)
754 }
755
756 Validator&
758 {
759 assert(v < validators_.size());
760 return validators_[v];
761 }
762
765 {
766 return overlay_;
767 }
768
769 void
770 enableLink(std::uint16_t validatorId, Peer::id_t peer, bool enable)
771 {
772 auto it = std::ranges::find_if(validators_, [&](auto& v) { return v.id() == validatorId; });
773 assert(it != validators_.end());
774 if (enable)
775 {
776 it->linkUp(peer);
777 }
778 else
779 {
780 it->linkDown(peer);
781 }
782 }
783
784 void
786 {
787 // Send unsquelch to the Peer on all links. This way when
788 // the Peer "reconnects" it starts sending messages on the link.
789 // We expect that if a Peer disconnects and then reconnects, it's
790 // unsquelched.
791 protocol::TMSquelch squelch;
792 squelch.set_squelch(false);
793 for (auto& v : validators_)
794 {
795 PublicKey const key = v;
796 squelch.clear_validatorpubkey();
797 squelch.set_validatorpubkey(key.data(), key.size());
798 v.forLinks({peer}, [&](Link& l, MessageSPtr) {
800 });
801 }
802 }
803
804 static void
806 {
807 auto size = max - min;
809 std::iota(s.begin(), s.end(), min); // NOLINT(modernize-use-ranges)
811 std::mt19937 g(d());
812 std::shuffle(s.begin(), s.end(), g);
813 for (auto v : s)
814 f(v);
815 }
816
817 void
819 LinkIterCB link,
820 std::uint16_t nValidators = kMaxValidators,
821 std::uint32_t nMessages = kMaxMessages,
822 bool purge = true,
823 bool resetClock = true)
824 {
825 if (resetClock)
827
828 if (purge)
829 {
830 purgePeers();
831 overlay_.resetPeers();
832 }
833
834 for (int m = 0; m < nMessages; ++m)
835 {
837 forRand(0, nValidators, [&](std::uint32_t v) { validators_[v].forLinks(link); });
838 }
839 }
840
842 bool
844 {
845 for (auto& v : validators_)
846 {
847 if (overlay_.isSelected(v, id))
848 return true;
849 }
850 return false;
851 }
852
857 bool
859 {
860 for (auto& v : validators_)
861 {
862 if (!overlay_.isSelected(v, peer))
863 continue;
864 auto peers = overlay_.getPeers(v);
865 for (auto& [_, v] : peers)
866 {
867 (void)_;
868 if (std::get<reduce_relay::PeerState>(v) == reduce_relay::PeerState::Squelched)
869 return false;
870 }
871 }
872 return true;
873 }
874
875private:
878};
879
881{
884
885protected:
886 void
888 {
889 auto peers = network_.overlay().getPeers(network_.validator(validator));
890 std::cout << msg << " "
891 << "num peers " << (int)network_.overlay().getNumPeers() << std::endl;
892 for (auto& [k, v] : peers)
893 std::cout << k << ":" << (int)std::get<reduce_relay::PeerState>(v) << " ";
895 }
896
898 static Peer::id_t
900 PublicKey const& validator,
901 PeerWPtr const& peerPtr,
903 {
904 protocol::TMSquelch squelch;
905 bool const res = static_cast<bool>(duration);
906 squelch.set_squelch(res);
907 squelch.set_validatorpubkey(validator.data(), validator.size());
908 if (res)
909 squelch.set_squelchduration(*duration);
910 auto sp = peerPtr.lock();
911 assert(sp);
913 return sp->id();
914 }
915
916 enum class State { On, Off, WaitReset };
917 enum class EventType { LinkDown = 0, PeerDisconnected = 1 };
918 // Link down or Peer disconnect event
919 // TBD - add new peer event
920 // TBD - add overlapping type of events at any
921 // time in any quantity
934
938 void
940 {
944
945 network_.reset();
946 network_.propagate([&](Link& link, MessageSPtr m) {
947 auto& validator = link.validator();
948 auto now = ManualClock::now();
949
950 bool squelched = false;
952
953 link.send(
954 m, [&](PublicKey const& key, PeerWPtr const& peerPtr, std::uint32_t duration) {
955 assert(key == validator);
956 auto p = sendSquelch(key, peerPtr, duration);
957 squelched = true;
958 str << p << " ";
959 });
960
961 if (squelched)
962 {
963 auto selected = network_.overlay().getSelected(validator);
964 str << " selected: ";
965 for (auto s : selected)
966 str << s << " ";
967 if (log)
968 {
969 std::cout << (double)reduce_relay::epoch<milliseconds>(now).count() / 1000.
970 << " random, squelched, validator: " << validator.id()
971 << " peers: " << str.str() << std::endl;
972 }
973 auto countingState = network_.overlay().isCountingState(validator);
974 BEAST_EXPECT(
975 countingState == false &&
976 selected.size() == env_.app().config().vpReduceRelaySquelchMaxSelectedPeers);
977 }
978
979 // Trigger Link Down or Peer Disconnect event
980 // Only one Link Down at a time
981 if (events[EventType::LinkDown].state == State::Off)
982 {
983 auto update = [&](EventType event) {
984 events[event].cnt++;
985 events[event].validator = validator.id();
986 events[event].key = validator;
987 events[event].peer = link.peerId();
988 events[event].state = State::On;
989 events[event].time = now;
990 if (event == EventType::LinkDown)
991 {
992 network_.enableLink(validator.id(), link.peerId(), false);
993 events[event].isSelected =
994 network_.overlay().isSelected(validator, link.peerId());
995 }
996 else
997 {
998 events[event].isSelected = network_.isSelected(link.peerId());
999 }
1000 };
1001 auto r = randInt(0, 1000);
1002 if (r == (int)EventType::LinkDown || r == (int)EventType::PeerDisconnected)
1003 {
1004 update(static_cast<EventType>(r));
1005 }
1006 }
1007
1008 if (events[EventType::PeerDisconnected].state == State::On)
1009 {
1010 auto& event = events[EventType::PeerDisconnected];
1011 bool const allCounting = network_.allCounting(event.peer);
1012 network_.overlay().deletePeer(
1013 event.peer, [&](PublicKey const& v, PeerWPtr const& peerPtr) {
1014 if (event.isSelected)
1015 sendSquelch(v, peerPtr, {});
1016 event.handled = true;
1017 });
1018 // Should only be unsquelched if the peer is in Selected state
1019 // If in Selected state it's possible unsquelching didn't
1020 // take place because there is no peers in Squelched state in
1021 // any of the slots where the peer is in Selected state
1022 // (allCounting is true)
1023 bool const handled = (!event.isSelected && !event.handled) ||
1024 (event.isSelected && (event.handled || allCounting));
1025 BEAST_EXPECT(handled);
1026 event.state = State::Off;
1027 event.isSelected = false;
1028 event.handledCnt += handled;
1029 event.handled = false;
1030 network_.onDisconnectPeer(event.peer);
1031 }
1032
1033 auto& event = events[EventType::LinkDown];
1034 // Check every sec for idled peers. Idled peers are
1035 // created by Link Down event.
1036 if (now - lastCheck > milliseconds(1000))
1037 {
1038 lastCheck = now;
1039 // Check if Link Down event must be handled by
1040 // deleteIdlePeer(): 1) the peer is in Selected state;
1041 // 2) the peer has not received any messages for IDLED time;
1042 // 3) there are peers in Squelched state in the slot.
1043 // 4) peer is in Slot's peers_ (if not then it is deleted
1044 // by Slots::deleteIdlePeers())
1045 bool mustHandle = false;
1046 if (event.state == State::On && BEAST_EXPECT(event.key))
1047 {
1048 event.isSelected = network_.overlay().isSelected(*event.key, event.peer);
1049 auto peers = network_.overlay().getPeers(*event.key);
1050 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1051 std::get<3>(peers[event.peer]);
1052 mustHandle = event.isSelected &&
1054 network_.overlay().inState(*event.key, reduce_relay::PeerState::Squelched) >
1055 0 &&
1056 peers.contains(event.peer);
1057 }
1058 network_.overlay().deleteIdlePeers([&](PublicKey const& v, PeerWPtr const& ptr) {
1059 event.handled = true;
1060 if (mustHandle && v == event.key)
1061 {
1062 event.state = State::WaitReset;
1063 sendSquelch(validator, ptr, {});
1064 }
1065 });
1066 bool const handled = (event.handled && event.state == State::WaitReset) ||
1067 (!event.handled && !mustHandle);
1068 BEAST_EXPECT(handled);
1069 }
1070 if (event.state == State::WaitReset ||
1071 (event.state == State::On &&
1072 (now - event.time > (reduce_relay::kIdled + seconds(2)))))
1073 {
1074 bool const handled = event.state == State::WaitReset || !event.handled;
1075 BEAST_EXPECT(handled);
1076 event.state = State::Off;
1077 event.isSelected = false;
1078 event.handledCnt += handled;
1079 event.handled = false;
1080 network_.enableLink(event.validator, event.peer, true);
1081 }
1082 });
1083
1084 auto& down = events[EventType::LinkDown];
1085 auto& disconnected = events[EventType::PeerDisconnected];
1086 // It's possible the last Down Link event is not handled
1087 BEAST_EXPECT(down.handledCnt >= down.cnt - 1);
1088 // All Peer Disconnect events must be handled
1089 BEAST_EXPECT(disconnected.cnt == disconnected.handledCnt);
1090 if (log)
1091 {
1092 std::cout << "link down count: " << down.cnt << "/" << down.handledCnt
1093 << " peer disconnect count: " << disconnected.cnt << "/"
1094 << disconnected.handledCnt;
1095 }
1096 }
1097
1098 bool
1099 checkCounting(PublicKey const& validator, bool isCountingState)
1100 {
1101 auto countingState = network_.overlay().isCountingState(validator);
1102 BEAST_EXPECT(countingState == isCountingState);
1103 return countingState == isCountingState;
1104 }
1105
1106 void
1107 doTest(std::string const& msg, bool log, std::function<void(bool)> f)
1108 {
1109 testcase(msg);
1110 f(log);
1111 }
1112
1118 void
1120 {
1121 doTest("Initial Round", log, [this](bool log) { BEAST_EXPECT(propagateAndSquelch(log)); });
1122 }
1123
1127 void
1129 {
1130 doTest("Peer Unsquelched Too Soon", log, [this](bool log) {
1131 BEAST_EXPECT(propagateNoSquelch(log, 1, false, false, false));
1132 });
1133 }
1134
1138 void
1140 {
1142 doTest("Peer Unsquelched", log, [this](bool log) {
1143 BEAST_EXPECT(propagateNoSquelch(log, 2, true, true, false));
1144 });
1145 }
1146
1148 bool
1149 propagateAndSquelch(bool log, bool purge = true, bool resetClock = true)
1150 {
1151 int n = 0;
1152 network_.propagate(
1153 [&](Link& link, MessageSPtr message) {
1154 std::uint16_t squelched = 0;
1155 link.send(
1156 message,
1157 [&](PublicKey const& key, PeerWPtr const& peerPtr, std::uint32_t duration) {
1158 squelched++;
1159 sendSquelch(key, peerPtr, duration);
1160 });
1161 if (squelched)
1162 {
1163 BEAST_EXPECT(
1164 squelched ==
1165 kMaxPeers - env_.app().config().vpReduceRelaySquelchMaxSelectedPeers);
1166 n++;
1167 }
1168 },
1169 1,
1171 purge,
1172 resetClock);
1173 auto selected = network_.overlay().getSelected(network_.validator(0));
1174 BEAST_EXPECT(selected.size() == env_.app().config().vpReduceRelaySquelchMaxSelectedPeers);
1175 BEAST_EXPECT(n == 1); // only one selection round
1176 auto res = checkCounting(network_.validator(0), false);
1177 BEAST_EXPECT(res);
1178 return n == 1 && res;
1179 }
1180
1182 bool
1184 bool log,
1185 std::uint16_t nMessages,
1186 bool countingState,
1187 bool purge = true,
1188 bool resetClock = true)
1189 {
1190 bool squelched = false;
1191 network_.propagate(
1192 [&](Link& link, MessageSPtr message) {
1193 link.send(
1194 message,
1195 [&](PublicKey const& key, PeerWPtr const& peerPtr, std::uint32_t duration) {
1196 squelched = true;
1197 BEAST_EXPECT(false);
1198 });
1199 },
1200 1,
1201 nMessages,
1202 purge,
1203 resetClock);
1204 auto res = checkCounting(network_.validator(0), countingState);
1205 return !squelched && res;
1206 }
1207
1211 void
1213 {
1214 doTest("New Peer", log, [this](bool log) {
1215 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1216 network_.addPeer();
1217 BEAST_EXPECT(propagateNoSquelch(log, 1, true, false, false));
1218 });
1219 }
1220
1223 void
1225 {
1226 doTest("Selected Peer Disconnects", log, [this](bool log) {
1228 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1229 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1230 std::uint16_t unsquelched = 0;
1231 network_.overlay().deletePeer(
1232 id, [&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; });
1233 BEAST_EXPECT(
1234 unsquelched ==
1235 kMaxPeers - env_.app().config().vpReduceRelaySquelchMaxSelectedPeers);
1236 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1237 });
1238 }
1239
1242 void
1244 {
1245 doTest("Selected Peer Stops Relaying", log, [this](bool log) {
1247 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1249 std::uint16_t unsquelched = 0;
1250 network_.overlay().deleteIdlePeers(
1251 [&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; });
1252 auto peers = network_.overlay().getPeers(network_.validator(0));
1253 BEAST_EXPECT(
1254 unsquelched ==
1255 kMaxPeers - env_.app().config().vpReduceRelaySquelchMaxSelectedPeers);
1256 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1257 });
1258 }
1259
1262 void
1264 {
1265 doTest("Squelched Peer Disconnects", log, [this](bool log) {
1267 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1268 auto peers = network_.overlay().getPeers(network_.validator(0));
1269 auto it = std::ranges::find_if(peers, [&](auto it) {
1270 return std::get<reduce_relay::PeerState>(it.second) ==
1272 });
1273 assert(it != peers.end());
1274 std::uint16_t unsquelched = 0;
1275 network_.overlay().deletePeer(
1276 it->first, [&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; });
1277 BEAST_EXPECT(unsquelched == 0);
1278 BEAST_EXPECT(checkCounting(network_.validator(0), false));
1279 });
1280 }
1281
1282 void
1284 {
1285 doTest("Test Config - squelch enabled (legacy)", log, [&](bool log) {
1286 Config c;
1287
1288 std::string const toLoad(R"xrpldConfig(
1289[reduce_relay]
1290vp_enable=1
1291)xrpldConfig");
1292
1293 c.loadFromString(toLoad);
1294 BEAST_EXPECT(c.vpReduceRelayBaseSquelchEnable == true);
1295 });
1296
1297 doTest("Test Config - squelch disabled (legacy)", log, [&](bool log) {
1298 Config c;
1299
1300 std::string toLoad(R"xrpldConfig(
1301[reduce_relay]
1302vp_enable=0
1303)xrpldConfig");
1304
1305 c.loadFromString(toLoad);
1306 BEAST_EXPECT(c.vpReduceRelayBaseSquelchEnable == false);
1307
1308 Config c1;
1309
1310 toLoad = R"xrpldConfig(
1311[reduce_relay]
1312)xrpldConfig";
1313
1314 c1.loadFromString(toLoad);
1315 BEAST_EXPECT(c1.vpReduceRelayBaseSquelchEnable == false);
1316 });
1317
1318 doTest("Test Config - squelch enabled", log, [&](bool log) {
1319 Config c;
1320
1321 std::string const toLoad(R"xrpldConfig(
1322[reduce_relay]
1323vp_base_squelch_enable=1
1324)xrpldConfig");
1325
1326 c.loadFromString(toLoad);
1327 BEAST_EXPECT(c.vpReduceRelayBaseSquelchEnable == true);
1328 });
1329
1330 doTest("Test Config - squelch disabled", log, [&](bool log) {
1331 Config c;
1332
1333 std::string const toLoad(R"xrpldConfig(
1334[reduce_relay]
1335vp_base_squelch_enable=0
1336)xrpldConfig");
1337
1338 c.loadFromString(toLoad);
1339 BEAST_EXPECT(c.vpReduceRelayBaseSquelchEnable == false);
1340 });
1341
1342 doTest("Test Config - legacy and new", log, [&](bool log) {
1343 Config c;
1344
1345 std::string const toLoad(R"xrpldConfig(
1346[reduce_relay]
1347vp_base_squelch_enable=0
1348vp_enable=0
1349)xrpldConfig");
1350
1351 std::string error;
1352 auto const expectedError =
1353 "Invalid reduce_relay"
1354 " cannot specify both vp_base_squelch_enable and vp_enable "
1355 "options. "
1356 "vp_enable was deprecated and replaced by "
1357 "vp_base_squelch_enable";
1358
1359 try
1360 {
1361 c.loadFromString(toLoad);
1362 }
1363 catch (std::runtime_error const& e)
1364 {
1365 error = e.what();
1366 }
1367
1368 BEAST_EXPECT(error == expectedError);
1369 });
1370
1371 doTest("Test Config - max selected peers", log, [&](bool log) {
1372 Config c;
1373
1374 std::string toLoad(R"xrpldConfig(
1375[reduce_relay]
1376)xrpldConfig");
1377
1378 c.loadFromString(toLoad);
1379 BEAST_EXPECT(c.vpReduceRelaySquelchMaxSelectedPeers == 5);
1380
1381 Config c1;
1382
1383 toLoad = R"xrpldConfig(
1384[reduce_relay]
1385vp_base_squelch_max_selected_peers=6
1386)xrpldConfig";
1387
1388 c1.loadFromString(toLoad);
1389 BEAST_EXPECT(c1.vpReduceRelaySquelchMaxSelectedPeers == 6);
1390
1392
1393 toLoad = R"xrpldConfig(
1394[reduce_relay]
1395vp_base_squelch_max_selected_peers=2
1396)xrpldConfig";
1397
1398 std::string error;
1399 auto const expectedError =
1400 "Invalid reduce_relay"
1401 " vp_base_squelch_max_selected_peers must be "
1402 "greater than or equal to 3";
1403 try
1404 {
1405 c2.loadFromString(toLoad);
1406 }
1407 catch (std::runtime_error const& e)
1408 {
1409 error = e.what();
1410 }
1411
1412 BEAST_EXPECT(error == expectedError);
1413 });
1414 }
1415
1416 void
1417 testBaseSquelchReady(bool log)
1418 {
1419 doTest("BaseSquelchReady", log, [&](bool log) {
1421 auto createSlots = [&](bool baseSquelchEnabled) -> reduce_relay::Slots<ManualClock> {
1422 env_.app().config().vpReduceRelayBaseSquelchEnable = baseSquelchEnabled;
1424 env_.app(), network_.overlay(), env_.app().config());
1425 };
1426 // base squelching must not be ready if squelching is disabled
1427 BEAST_EXPECT(!createSlots(false).baseSquelchReady());
1428
1429 // base squelch must not be ready as not enough time passed from
1430 // bootup
1431 BEAST_EXPECT(!createSlots(true).baseSquelchReady());
1432
1434
1435 // base squelch enabled and bootup time passed
1436 BEAST_EXPECT(createSlots(true).baseSquelchReady());
1437
1438 // even if time passed, base squelching must not be ready if turned
1439 // off in the config
1440 BEAST_EXPECT(!createSlots(false).baseSquelchReady());
1441 });
1442 }
1443
1444 void
1445 testInternalHashRouter(bool log)
1446 {
1447 doTest("Duplicate Message", log, [&](bool log) {
1448 network_.reset();
1449 // update message count for the same peer/validator
1450 std::int16_t const nMessages = 5;
1451 for (int i = 0; i < nMessages; i++)
1452 {
1453 uint256 const key(i);
1454 network_.overlay().updateSlotAndSquelch(
1455 key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {
1456 });
1458 auto peers = network_.overlay().getPeers(network_.validator(0));
1459 // first message changes Slot state to Counting and is not counted,
1460 // hence '-1'.
1461 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1462 // add duplicate
1463 uint256 const key(nMessages - 1);
1464 network_.overlay().updateSlotAndSquelch(
1465 key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1466 // confirm the same number of messages
1467 peers = network_.overlay().getPeers(network_.validator(0));
1468 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1469 // advance the clock
1471 network_.overlay().updateSlotAndSquelch(
1472 key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1473 peers = network_.overlay().getPeers(network_.validator(0));
1474 // confirm message number increased
1475 BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
1476 });
1477 }
1478
1479 struct Handler : public reduce_relay::SquelchHandler
1480 {
1481 Handler() = default;
1482 void
1483 squelch(PublicKey const&, Peer::id_t, std::uint32_t duration) const override
1484 {
1485 maxDuration = std::max<uint32_t>(duration, maxDuration);
1486 }
1487 void
1488 unsquelch(PublicKey const&, Peer::id_t) const override
1489 {
1490 }
1491 mutable int maxDuration{0};
1492 };
1493
1494 void
1495 testRandomSquelch(bool l)
1496 {
1497 doTest("Random Squelch", l, [&](bool l) {
1498 PublicKey validator = std::get<0>(randomKeyPair(KeyType::Ed25519));
1499 Handler handler;
1500
1501 auto run = [&](int npeers) {
1502 handler.maxDuration = 0;
1503 reduce_relay::Slots<ManualClock> slots(env_.app(), handler, env_.app().config());
1504 // 1st message from a new peer switches the slot
1505 // to counting state and resets the counts of all peers +
1506 // MAX_MESSAGE_THRESHOLD + 1 messages to reach the threshold
1507 // and switch the slot's state to peer selection.
1508 for (int m = 1; m <= reduce_relay::kMaxMessageThreshold + 2; m++)
1509 {
1510 for (int peer = 0; peer < npeers; peer++)
1511 {
1512 // make unique message hash to make the
1513 // slot's internal hash router accept the message
1514 std::uint64_t const mid = (m * 1000) + peer;
1515 uint256 const message{mid};
1516 slots.updateSlotAndSquelch(
1517 message, validator, peer, protocol::MessageType::mtVALIDATION);
1518 }
1519 }
1520 // make Slot's internal hash router expire all messages
1522 };
1523
1524 using namespace reduce_relay;
1525 // expect max duration less than kMaxUnsquelchExpireDefault with
1526 // less than or equal to 60 peers
1527 run(20);
1528 BEAST_EXPECT(
1529 handler.maxDuration >= kMinUnsquelchExpire.count() &&
1530 handler.maxDuration <= kMaxUnsquelchExpireDefault.count());
1531 run(60);
1532 BEAST_EXPECT(
1533 handler.maxDuration >= kMinUnsquelchExpire.count() &&
1534 handler.maxDuration <= kMaxUnsquelchExpireDefault.count());
1535 // expect max duration greater than kMinUnsquelchExpire and less
1536 // than kMaxUnsquelchExpirePeers with peers greater than 60
1537 // and less than 360
1538 run(350);
1539 // can't make this condition stronger. squelch
1540 // duration is probabilistic and max condition may still fail.
1541 // log when the value is low
1542 BEAST_EXPECT(
1543 handler.maxDuration >= kMinUnsquelchExpire.count() &&
1544 handler.maxDuration <= kMaxUnsquelchExpirePeers.count());
1545 using namespace beast::unit_test::detail;
1546 if (handler.maxDuration <= kMaxUnsquelchExpireDefault.count())
1547 {
1548 log << makeReason("warning: squelch duration is low", __FILE__, __LINE__)
1549 << std::endl
1550 << std::flush;
1551 }
1552 // more than 400 is still less than kMaxUnsquelchExpirePeers
1553 run(400);
1554 BEAST_EXPECT(
1555 handler.maxDuration >= kMinUnsquelchExpire.count() &&
1556 handler.maxDuration <= kMaxUnsquelchExpirePeers.count());
1557 if (handler.maxDuration <= kMaxUnsquelchExpireDefault.count())
1558 {
1559 log << makeReason("warning: squelch duration is low", __FILE__, __LINE__)
1560 << std::endl
1561 << std::flush;
1562 }
1563 });
1564 }
1565
1566 void
1567 testHandshake(bool log)
1568 {
1569 doTest("Handshake", log, [&](bool log) {
1570 auto setEnv = [&](bool enable) {
1571 Config c;
1572 std::stringstream str;
1573 str << "[reduce_relay]\n"
1574 << "vp_enable=" << enable << "\n"
1575 << "[compression]\n"
1576 << "1\n";
1577 c.loadFromString(str.str());
1578 env_.app().config().vpReduceRelayBaseSquelchEnable =
1579 c.vpReduceRelayBaseSquelchEnable;
1580
1581 env_.app().config().compression = c.compression;
1582 };
1583 auto handshake = [&](int outboundEnable, int inboundEnable) {
1584 beast::IP::Address const addr = boost::asio::ip::make_address("172.1.1.100");
1585
1586 setEnv(outboundEnable);
1587 auto request = xrpl::makeRequest(
1588 true,
1589 env_.app().config().compression,
1590 false,
1591 env_.app().config().txReduceRelayEnable,
1592 env_.app().config().vpReduceRelayBaseSquelchEnable);
1593 http_request_type httpRequest;
1594 httpRequest.version(request.version());
1595 httpRequest.base() = request.base();
1596 // feature enabled on the peer's connection only if both sides
1597 // are enabled
1598 auto const peerEnabled = inboundEnable && outboundEnable;
1599 // inbound is enabled if the request's header has the feature
1600 // enabled and the peer's configuration is enabled
1601 auto const inboundEnabled =
1602 peerFeatureEnabled(httpRequest, kFeatureVprr, inboundEnable);
1603 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1604
1605 setEnv(inboundEnable);
1606 auto httpResp = xrpl::makeResponse(
1607 true, httpRequest, addr, addr, uint256{1}, 1, {1, 0}, env_.app());
1608 // outbound is enabled if the response's header has the feature
1609 // enabled and the peer's configuration is enabled
1610 auto const outboundEnabled =
1611 peerFeatureEnabled(httpResp, kFeatureVprr, outboundEnable);
1612 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1613 };
1614 handshake(1, 1);
1615 handshake(1, 0);
1616 handshake(0, 1);
1617 handshake(0, 0);
1618 });
1619 }
1620
1621 jtx::Env env_;
1622 Network network_;
1623
1624public:
1625 reduce_relay_test()
1626 : env_(*this, jtx::envconfig([](std::unique_ptr<Config> cfg) {
1627 cfg->vpReduceRelayBaseSquelchEnable = true;
1628 cfg->vpReduceRelaySquelchMaxSelectedPeers = 6;
1629 return cfg;
1630 }))
1631 , network_(env_.app())
1632 {
1633 }
1634
1635 void
1636 run() override
1637 {
1638 bool const log = false;
1639 testConfig(log);
1640 testInitialRound(log);
1641 testPeerUnsquelchedTooSoon(log);
1642 testPeerUnsquelched(log);
1643 testNewPeer(log);
1644 testSquelchedPeerDisconnects(log);
1645 testSelectedPeerDisconnects(log);
1646 testSelectedPeerStopsRelaying(log);
1647 testInternalHashRouter(log);
1648 testRandomSquelch(log);
1649 testHandshake(log);
1650 testBaseSquelchReady(log);
1651 }
1652};
1653
1655{
1656 void
1658 {
1659 doTest("Random Test", log, [&](bool log) { random(log); });
1660 }
1661
1662 void
1663 run() override
1664 {
1665 bool const log = false;
1666 testRandom(log);
1667 }
1668};
1669
1671BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, overlay, xrpl);
1672
1673} // namespace xrpl::test
T back_inserter(T... args)
T begin(T... args)
A version-independent IP address and port combination.
Definition IPEndpoint.h:17
A generic endpoint for log messages.
Definition Journal.h:38
A testsuite class.
Definition suite.h:50
LogOs< char > log
Logging output stream.
Definition suite.h:146
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
Represents a JSON value.
Definition json_value.h:130
std::size_t vpReduceRelaySquelchMaxSelectedPeers
Definition Config.h:239
bool vpReduceRelayBaseSquelchEnable
Definition Config.h:233
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition Config.cpp:473
Represents a peer connection in the overlay.
std::uint32_t id_t
Uniquely identifies a peer.
A public key.
Definition PublicKey.h:42
std::uint8_t const * data() const noexcept
Definition PublicKey.h:67
static std::size_t size() noexcept
Definition PublicKey.h:73
A consumption charge.
Definition Charge.h:9
Service registry for dependency injection.
An immutable linear range of bytes.
Definition Slice.h:26
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...
Maintains squelching of relaying messages from validators.
Definition Squelch.h:16
Manually advanced clock.
static void randAdvance(milliseconds min, milliseconds max)
static duration randDuration(milliseconds min, milliseconds max)
static void advance(duration d) noexcept
std::chrono::time_point< ManualClock > time_point
static void reset() noexcept
static time_point now() noexcept
std::chrono::duration< std::uint32_t, period > duration
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...
static void forRand(std::uint32_t min, std::uint32_t max, std::function< void(std::uint32_t)> f)
bool isSelected(Peer::id_t id)
Is peer in Selected state in any of the slots.
void enableLink(std::uint16_t validatorId, Peer::id_t peer, bool enable)
void propagate(LinkIterCB link, std::uint16_t nValidators=kMaxValidators, std::uint32_t nMessages=kMaxMessages, bool purge=true, bool resetClock=true)
std::vector< Validator > validators_
Network(Application &app)
Validator & validator(std::uint16_t v)
void onDisconnectPeer(Peer::id_t peer)
bool isSelected(PublicKey const &validator, Peer::id_t peer)
std::uint16_t getNumPeers() const
std::optional< Peer::id_t > deleteLastPeer()
std::unordered_map< id_t, std::tuple< reduce_relay::PeerState, std::uint16_t, std::uint32_t, std::uint32_t > > getPeers(PublicKey const &validator)
std::set< id_t > getSelected(PublicKey const &validator)
PeerSPtr addPeer(bool useCache=true)
void squelch(PublicKey const &validator, Peer::id_t id, std::uint32_t squelchDuration) const override
Squelch handler.
void deletePeer(Peer::id_t id, bool useCache=true)
std::unordered_map< Peer::id_t, PeerSPtr > Peers
void unsquelch(PublicKey const &validator, Peer::id_t id) const override
Unsquelch handler.
void deleteIdlePeers(UnsquelchCB f) override
void deletePeer(id_t id, UnsquelchCB f) override
id_t getSelectedPeer(PublicKey const &validator)
std::uint16_t inState(PublicKey const &validator, reduce_relay::PeerState state)
bool isCountingState(PublicKey const &validator)
~OverlaySim() override=default
void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, Peer::id_t id, SquelchCB f, protocol::MessageType type=protocol::mtVALIDATION) override
reduce_relay::Slots< ManualClock > slots_
Simulate server's OverlayImpl.
virtual void deleteIdlePeers(UnsquelchCB)=0
virtual void deletePeer(Peer::id_t, UnsquelchCB)=0
virtual ~Overlay()=default
virtual void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, Peer::id_t id, SquelchCB f, protocol::MessageType type=protocol::mtVALIDATION)=0
void send(std::shared_ptr< Message > const &m) override
bool hasLedger(uint256 const &hash, std::uint32_t seq) const override
void addTxQueue(uint256 const &) override
Aggregate transaction's hash.
virtual void onMessage(protocol::TMSquelch const &squelch)=0
bool compressionEnabled() const override
virtual void onMessage(MessageSPtr const &m, SquelchCB f)=0
void sendTxQueue() override
Send aggregated transactions' hashes.
void removeTxQueue(uint256 const &) override
Remove hash from the transactions' hashes queue.
json::Value json() override
std::optional< std::size_t > publisherListSequence(PublicKey const &) const override
bool supportsFeature(ProtocolFeature f) const override
bool hasTxSet(uint256 const &hash) const override
void send(protocol::TMSquelch const &squelch)
void ledgerRange(std::uint32_t &minSeq, std::uint32_t &maxSeq) const override
~PeerPartial() override=default
bool cluster() const override
Returns true if this connection is a member of the cluster.
uint256 const & getClosedLedgerHash() const override
bool hasRange(std::uint32_t uMin, std::uint32_t uMax) 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.
beast::IP::Endpoint getRemoteAddress() const override
bool isHighLatency() const override
PublicKey const & getNodePublic() const override
void setPublisherListSequence(PublicKey const &, std::size_t const) override
bool txReduceRelayEnabled() const override
int getScore(bool) const override
~PeerSim() override=default
void onMessage(protocol::TMSquelch const &squelch) override
Remote Peer (Directly connected Peer).
reduce_relay::Squelch< ManualClock > squelch_
std::string const & fingerprint() const override
id_t id() const override
void onMessage(MessageSPtr const &m, SquelchCB f) override
Local Peer (PeerImp).
PeerSim(Overlay &overlay, beast::Journal journal)
void addPeer(PeerSPtr peer)
Validator & operator=(Validator &&)=default
void send(std::vector< Peer::id_t > peers, SquelchCB f)
Send to specific peers.
void send(SquelchCB f)
Send to all peers.
void forLinks(LinkIterCB f, bool simulateSlow=false)
void linkDown(Peer::id_t id)
Validator(Validator const &)=default
void linkUp(Peer::id_t id)
void deletePeer(Peer::id_t id)
void forLinks(std::vector< Peer::id_t > peers, LinkIterCB f)
Validator & operator=(Validator const &)=default
std::unordered_map< Peer::id_t, LinkSPtr > Links
std::uint16_t id() const
Validator(Validator &&)=default
static std::uint16_t sid
PublicKey const & key()
void printPeers(std::string const &msg, std::uint16_t validator=0)
void doTest(std::string const &msg, bool log, std::function< void(bool)> f)
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.
bool propagateAndSquelch(bool log, bool purge=true, bool resetClock=true)
Propagate enough messages to generate one squelch event.
static 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 random(bool log)
Randomly brings the link between a validator and a peer down.
void testSquelchedPeerDisconnects(bool log)
Squelched peer disconnects.
void testPeerUnsquelchedTooSoon(bool log)
Receiving message from squelched peer too soon should not change the slot's state to Counting.
reduce_relay::Slot< ManualClock > Slot
void testInitialRound(bool log)
Initial counting round: three peers receive message "faster" then others.
void testSelectedPeerStopsRelaying(bool log)
Selected peer stops relaying.
void testSelectedPeerDisconnects(bool log)
Selected peer disconnects.
bool checkCounting(PublicKey const &validator, bool isCountingState)
void testPeerUnsquelched(bool log)
Receiving message from squelched peer should change the slot's state to Counting.
void testNewPeer(bool log)
Receiving a message from new peer should change the slot's state to Counting.
T end(T... args)
T endl(T... args)
T find_if(T... args)
T flush(T... args)
T iota(T... args)
T lock(T... args)
T log(T... args)
T make_pair(T... args)
T make_shared(T... args)
T max(T... args)
T min(T... args)
boost::asio::ip::address Address
Definition IPAddress.h:19
static std::string makeReason(String const &reason, char const *file, int line)
Definition suite.h:23
STL namespace.
static constexpr uint16_t kMaxMessageThreshold
Unit epoch(TP const &t)
static constexpr auto kWaitOnBootup
PeerState
Peer's State.
static constexpr auto kIdled
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:28
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
static constexpr std::uint32_t kMaxMessages
std::function< void(Link &, MessageSPtr)> LinkIterCB
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
std::shared_ptr< Peer > PeerSPtr
static constexpr std::uint32_t kMaxPeers
BEAST_DEFINE_TESTSUITE_MANUAL(AMMCalc, app, xrpl)
std::shared_ptr< Message > MessageSPtr
static constexpr std::uint32_t kMaxValidators
std::shared_ptr< Link > LinkSPtr
std::weak_ptr< Peer > PeerWPtr
std::function< void(PublicKey const &, PeerWPtr const &)> UnsquelchCB
std::function< void(PublicKey const &, PeerWPtr const &, std::uint32_t)> SquelchCB
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
KeyType
Definition KeyType.h:8
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
int run(int argc, char **argv)
Definition Main.cpp:354
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
std::enable_if_t< std::is_integral_v< Integral >, Integral > randInt()
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
http_response_type makeResponse(bool crawlPublic, http_request_type const &req, beast::IP::Address publicIp, beast::IP::Address remoteIp, uint256 const &sharedValue, std::optional< std::uint32_t > networkID, ProtocolVersion protocol, Application &app)
Make http response.
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
bool peerFeatureEnabled(Headers const &request, std::string const &feature, std::string value, bool config)
Check if a feature should be enabled for a peer.
Definition Handshake.h:171
constexpr Number squelch(Number const &x, Number const &limit) noexcept
Definition Number.h:854
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:12
BaseUInt< 256 > uint256
Definition base_uint.h:562
static constexpr char kFeatureVprr[]
Definition Handshake.h:120
T dynamic_pointer_cast(T... args)
T shuffle(T... args)
T size(T... args)
T str(T... args)
T transform(T... args)
T what(T... args)