rippled
Loading...
Searching...
No Matches
reduce_relay_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright 2020 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
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>
28
29#include <boost/thread.hpp>
30
31#include <numeric>
32#include <optional>
33
34namespace ripple {
35
36namespace test {
37
38using namespace std::chrono;
39
40class Link;
41
46using SquelchCB =
47 std::function<void(PublicKey const&, PeerWPtr const&, std::uint32_t)>;
48using UnsquelchCB = std::function<void(PublicKey const&, PeerWPtr const&)>;
50
51static constexpr std::uint32_t MAX_PEERS = 10;
52static constexpr std::uint32_t MAX_VALIDATORS = 10;
53static constexpr std::uint32_t MAX_MESSAGES = 200000;
54
58class PeerPartial : public Peer
59{
60public:
63 {
64 }
65
67 virtual ~PeerPartial()
68 {
69 }
70 virtual void
72 virtual void
73 onMessage(protocol::TMSquelch const& squelch) = 0;
74 void
75 send(protocol::TMSquelch const& squelch)
76 {
78 }
79
80 // dummy implementation
81 void
82 send(std::shared_ptr<Message> const& m) override
83 {
84 }
86 getRemoteAddress() const override
87 {
88 return {};
89 }
90 void
91 charge(Resource::Charge const& fee) override
92 {
93 }
94 bool
95 cluster() const override
96 {
97 return false;
98 }
99 bool
100 isHighLatency() const override
101 {
102 return false;
103 }
104 int
105 getScore(bool) const override
106 {
107 return 0;
108 }
109 PublicKey const&
110 getNodePublic() const override
111 {
112 return nodePublicKey_;
113 }
115 json() override
116 {
117 return {};
118 }
119 bool
121 {
122 return false;
123 }
125 publisherListSequence(PublicKey const&) const override
126 {
127 return {};
128 }
129 void
131 {
132 }
133 uint256 const&
134 getClosedLedgerHash() const override
135 {
136 static uint256 hash{};
137 return hash;
138 }
139 bool
140 hasLedger(uint256 const& hash, std::uint32_t seq) const override
141 {
142 return false;
143 }
144 void
145 ledgerRange(std::uint32_t& minSeq, std::uint32_t& maxSeq) const override
146 {
147 }
148 bool
149 hasTxSet(uint256 const& hash) const override
150 {
151 return false;
152 }
153 void
154 cycleStatus() override
155 {
156 }
157 bool
159 {
160 return false;
161 }
162 bool
163 compressionEnabled() const override
164 {
165 return false;
166 }
167 bool
168 txReduceRelayEnabled() const override
169 {
170 return false;
171 }
172 void
173 sendTxQueue() override
174 {
175 }
176 void
177 addTxQueue(const uint256&) override
178 {
179 }
180 void
181 removeTxQueue(const uint256&) override
182 {
183 }
184};
185
188{
189public:
190 typedef uint64_t rep;
194 inline static const bool is_steady = false;
195
196 static void
197 advance(duration d) noexcept
198 {
199 now_ += d;
200 }
201
202 static void
204 {
205 now_ += randDuration(min, max);
206 }
207
208 static void
209 reset() noexcept
210 {
211 now_ = time_point(seconds(0));
212 }
213
214 static time_point
215 now() noexcept
216 {
217 return now_;
218 }
219
220 static duration
222 {
223 return duration(milliseconds(rand_int(min.count(), max.count())));
224 }
225
226 explicit ManualClock() = default;
227
228private:
229 inline static time_point now_ = time_point(seconds(0));
230};
231
234{
235public:
236 Overlay() = default;
237 virtual ~Overlay() = default;
238
239 virtual void
241 uint256 const& key,
242 PublicKey const& validator,
243 Peer::id_t id,
244 SquelchCB f,
245 protocol::MessageType type = protocol::mtVALIDATION) = 0;
246
247 virtual void deleteIdlePeers(UnsquelchCB) = 0;
248
250};
251
252class Validator;
253
257class Link
258{
260
261public:
264 PeerSPtr peer,
265 Latency const& latency = {milliseconds(5), milliseconds(15)})
266 : validator_(validator), peer_(peer), latency_(latency), up_(true)
267 {
268 auto sp = peer_.lock();
269 assert(sp);
270 }
271 ~Link() = default;
272 void
274 {
275 if (!up_)
276 return;
277 auto sp = peer_.lock();
278 assert(sp);
279 auto peer = std::dynamic_pointer_cast<PeerPartial>(sp);
280 peer->onMessage(m, f);
281 }
282 Validator&
284 {
285 return validator_;
286 }
287 void
288 up(bool linkUp)
289 {
290 up_ = linkUp;
291 }
294 {
295 auto p = peer_.lock();
296 assert(p);
297 return p->id();
298 }
301 {
302 auto p = peer_.lock();
303 assert(p);
304 return p;
305 }
306
307private:
311 bool up_;
312};
313
316{
318
319public:
321 {
322 protocol::TMValidation v;
323 v.set_validation("validation");
324 message_ = std::make_shared<Message>(v, protocol::mtVALIDATION, pkey_);
325 id_ = sid_++;
326 }
327 Validator(Validator const&) = default;
328 Validator(Validator&&) = default;
329 Validator&
330 operator=(Validator const&) = default;
331 Validator&
332 operator=(Validator&&) = default;
334 {
335 clear();
336 }
337
338 void
340 {
341 links_.clear();
342 }
343
344 static void
346 {
347 sid_ = 0;
348 }
349
350 PublicKey const&
352 {
353 return pkey_;
354 }
355
356 operator PublicKey() const
357 {
358 return pkey_;
359 }
360
361 void
363 {
365 std::make_pair(peer->id(), std::make_shared<Link>(*this, peer)));
366 }
367
368 void
370 {
371 links_.erase(id);
372 }
373
374 void
376 {
377 for (auto id : peers)
378 {
379 assert(links_.find(id) != links_.end());
380 f(*links_[id], message_);
381 }
382 }
383
384 void
385 for_links(LinkIterCB f, bool simulateSlow = false)
386 {
389 links_.begin(), links_.end(), std::back_inserter(v), [](auto& kv) {
390 return kv.second;
391 });
393 std::mt19937 g(d());
394 std::shuffle(v.begin(), v.end(), g);
395
396 for (auto& link : v)
397 {
398 f(*link, message_);
399 }
400 }
401
403 void
405 {
406 for_links(peers, [&](Link& link, MessageSPtr m) { link.send(m, f); });
407 }
408
410 void
412 {
413 for_links([&](Link& link, MessageSPtr m) { link.send(m, f); });
414 }
415
418 {
419 return message_;
420 }
421
424 {
425 return id_;
426 }
427
428 void
430 {
431 auto it = links_.find(id);
432 assert(it != links_.end());
433 it->second->up(true);
434 }
435
436 void
438 {
439 auto it = links_.find(id);
440 assert(it != links_.end());
441 it->second->up(false);
442 }
443
444private:
448 inline static std::uint16_t sid_ = 0;
450};
451
452class PeerSim : public PeerPartial, public std::enable_shared_from_this<PeerSim>
453{
454public:
456 PeerSim(Overlay& overlay, beast::Journal journal)
457 : overlay_(overlay), squelch_(journal)
458 {
459 id_ = sid_++;
460 }
461
462 ~PeerSim() = default;
463
464 id_t
465 id() const override
466 {
467 return id_;
468 }
469
470 static void
472 {
473 sid_ = 0;
474 }
475
477 void
478 onMessage(MessageSPtr const& m, SquelchCB f) override
479 {
480 auto validator = m->getValidatorKey();
481 assert(validator);
482 if (!squelch_.expireSquelch(*validator))
483 return;
484
486 }
487
489 virtual void
490 onMessage(protocol::TMSquelch const& squelch) override
491 {
492 auto validator = squelch.validatorpubkey();
493 PublicKey key(Slice(validator.data(), validator.size()));
494 if (squelch.squelch())
495 squelch_.addSquelch(
496 key, std::chrono::seconds{squelch.squelchduration()});
497 else
498 squelch_.removeSquelch(key);
499 }
500
501private:
502 inline static id_t sid_ = 0;
506};
507
509{
511
512public:
515 OverlaySim(Application& app) : slots_(app.logs(), *this), logs_(app.logs())
516 {
517 }
518
519 ~OverlaySim() = default;
520
521 void
523 {
524 peers_.clear();
526 slots_.deleteIdlePeers();
527 }
528
531 {
532 auto res = slots_.inState(validator, state);
533 return res ? *res : 0;
534 }
535
536 void
538 uint256 const& key,
539 PublicKey const& validator,
540 Peer::id_t id,
541 SquelchCB f,
542 protocol::MessageType type = protocol::mtVALIDATION) override
543 {
544 squelch_ = f;
545 slots_.updateSlotAndSquelch(key, validator, id, type);
546 }
547
548 void
550 {
551 unsquelch_ = f;
552 slots_.deletePeer(id, true);
553 }
554
555 void
557 {
558 unsquelch_ = f;
559 slots_.deleteIdlePeers();
560 }
561
563 addPeer(bool useCache = true)
564 {
565 PeerSPtr peer{};
566 Peer::id_t id;
567 if (peersCache_.empty() || !useCache)
568 {
569 peer = std::make_shared<PeerSim>(*this, logs_.journal("Squelch"));
570 id = peer->id();
571 }
572 else
573 {
574 auto it = peersCache_.begin();
575 peer = it->second;
576 id = it->first;
577 peersCache_.erase(it);
578 }
579 peers_.emplace(std::make_pair(id, peer));
580 return peer;
581 }
582
583 void
584 deletePeer(Peer::id_t id, bool useCache = true)
585 {
586 auto it = peers_.find(id);
587 assert(it != peers_.end());
588 deletePeer(id, [&](PublicKey const&, PeerWPtr) {});
589 if (useCache)
590 peersCache_.emplace(std::make_pair(id, it->second));
591 peers_.erase(it);
592 }
593
594 void
596 {
597 while (!peers_.empty())
598 deletePeer(peers_.begin()->first);
599 while (!peersCache_.empty())
600 addPeer();
601 }
602
605 {
606 if (peers_.empty())
607 return {};
608
609 std::uint8_t maxId = 0;
610
611 for (auto& [id, _] : peers_)
612 {
613 (void)_;
614 if (id > maxId)
615 maxId = id;
616 }
617
618 deletePeer(maxId, false);
619
620 return maxId;
621 }
622
623 bool
625 {
627 }
628
631 {
632 return slots_.getSelected(validator);
633 }
634
635 bool
637 {
638 auto selected = slots_.getSelected(validator);
639 return selected.find(peer) != selected.end();
640 }
641
642 id_t
644 {
645 auto selected = slots_.getSelected(validator);
646 assert(selected.size());
647 return *selected.begin();
648 }
649
651 id_t,
658 {
659 return slots_.getPeers(validator);
660 }
661
664 {
665 return peers_.size();
666 }
667
668private:
669 void
671 PublicKey const& validator,
672 Peer::id_t id,
673 std::uint32_t squelchDuration) const override
674 {
675 if (auto it = peers_.find(id); it != peers_.end())
676 squelch_(validator, it->second, squelchDuration);
677 }
678 void
679 unsquelch(PublicKey const& validator, Peer::id_t id) const override
680 {
681 if (auto it = peers_.find(id); it != peers_.end())
682 unsquelch_(validator, it->second);
683 }
690};
691
693{
694public:
696 {
697 init();
698 }
699
700 void
702 {
704 for (int p = 0; p < MAX_PEERS; p++)
705 {
706 auto peer = overlay_.addPeer();
707 for (auto& v : validators_)
708 v.addPeer(peer);
709 }
710 }
711
712 ~Network() = default;
713
714 void
716 {
717 validators_.clear();
718 overlay_.clear();
721 init();
722 }
723
726 {
727 auto peer = overlay_.addPeer();
728 for (auto& v : validators_)
729 v.addPeer(peer);
730 return peer->id();
731 }
732
733 void
735 {
736 auto id = overlay_.deleteLastPeer();
737
738 if (!id)
739 return;
740
741 for (auto& validator : validators_)
743 }
744
745 void
747 {
748 while (overlay_.getNumPeers() > MAX_PEERS)
750 }
751
752 Validator&
754 {
755 assert(v < validators_.size());
756 return validators_[v];
757 }
758
761 {
762 return overlay_;
763 }
764
765 void
766 enableLink(std::uint16_t validatorId, Peer::id_t peer, bool enable)
767 {
768 auto it =
769 std::find_if(validators_.begin(), validators_.end(), [&](auto& v) {
770 return v.id() == validatorId;
771 });
772 assert(it != validators_.end());
773 if (enable)
774 it->linkUp(peer);
775 else
776 it->linkDown(peer);
777 }
778
779 void
781 {
782 // Send unsquelch to the Peer on all links. This way when
783 // the Peer "reconnects" it starts sending messages on the link.
784 // We expect that if a Peer disconnects and then reconnects, it's
785 // unsquelched.
786 protocol::TMSquelch squelch;
787 squelch.set_squelch(false);
788 for (auto& v : validators_)
789 {
790 PublicKey key = v;
791 squelch.clear_validatorpubkey();
792 squelch.set_validatorpubkey(key.data(), key.size());
793 v.for_links({peer}, [&](Link& l, MessageSPtr) {
794 std::dynamic_pointer_cast<PeerSim>(l.getPeer())->send(squelch);
795 });
796 }
797 }
798
799 void
801 std::uint32_t min,
802 std::uint32_t max,
804 {
805 auto size = max - min;
807 std::iota(s.begin(), s.end(), min);
809 std::mt19937 g(d());
810 std::shuffle(s.begin(), s.end(), g);
811 for (auto v : s)
812 f(v);
813 }
814
815 void
817 LinkIterCB link,
818 std::uint16_t nValidators = MAX_VALIDATORS,
819 std::uint32_t nMessages = MAX_MESSAGES,
820 bool purge = true,
821 bool resetClock = true)
822 {
823 if (resetClock)
825
826 if (purge)
827 {
828 purgePeers();
830 }
831
832 for (int m = 0; m < nMessages; ++m)
833 {
835 for_rand(0, nValidators, [&](std::uint32_t v) {
836 validators_[v].for_links(link);
837 });
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) ==
870 return false;
871 }
872 }
873 return true;
874 }
875
876private:
879};
880
882{
885
886protected:
887 void
889 {
891 std::cout << msg << " " << "num peers "
892 << (int)network_.overlay().getNumPeers() << std::endl;
893 for (auto& [k, v] : peers)
894 std::cout << k << ":" << (int)std::get<reduce_relay::PeerState>(v)
895 << " ";
897 }
898
902 PublicKey const& validator,
903 PeerWPtr const& peerPtr,
905 {
906 protocol::TMSquelch squelch;
907 bool res = duration ? true : false;
908 squelch.set_squelch(res);
909 squelch.set_validatorpubkey(validator.data(), validator.size());
910 if (res)
911 squelch.set_squelchduration(*duration);
912 auto sp = peerPtr.lock();
913 assert(sp);
914 std::dynamic_pointer_cast<PeerSim>(sp)->send(squelch);
915 return sp->id();
916 }
917
918 enum State { On, Off, WaitReset };
920 // Link down or Peer disconnect event
921 // TBD - add new peer event
922 // TBD - add overlapping type of events at any
923 // time in any quantity
924 struct Event
925 {
929 bool isSelected_ = false;
934 bool handled_ = false;
935 };
936
940 void
942 {
944 {LinkDown, {}}, {PeerDisconnected, {}}};
946
947 network_.reset();
948 network_.propagate([&](Link& link, MessageSPtr m) {
949 auto& validator = link.validator();
950 auto now = ManualClock::now();
951
952 bool squelched = false;
954
955 link.send(
956 m,
957 [&](PublicKey const& key,
958 PeerWPtr const& peerPtr,
960 assert(key == validator);
961 auto p = sendSquelch(key, peerPtr, duration);
962 squelched = true;
963 str << p << " ";
964 });
965
966 if (squelched)
967 {
968 auto selected = network_.overlay().getSelected(validator);
969 str << " selected: ";
970 for (auto s : selected)
971 str << s << " ";
972 if (log)
974 << (double)reduce_relay::epoch<milliseconds>(now)
975 .count() /
976 1000.
977 << " random, squelched, validator: " << validator.id()
978 << " peers: " << str.str() << std::endl;
979 auto countingState =
981 BEAST_EXPECT(
982 countingState == false &&
983 selected.size() == reduce_relay::MAX_SELECTED_PEERS);
984 }
985
986 // Trigger Link Down or Peer Disconnect event
987 // Only one Link Down at a time
988 if (events[EventType::LinkDown].state_ == State::Off)
989 {
990 auto update = [&](EventType event) {
991 events[event].cnt_++;
992 events[event].validator_ = validator.id();
993 events[event].key_ = validator;
994 events[event].peer_ = link.peerId();
995 events[event].state_ = State::On;
996 events[event].time_ = now;
997 if (event == EventType::LinkDown)
998 {
1000 validator.id(), link.peerId(), false);
1001 events[event].isSelected_ =
1003 validator, link.peerId());
1004 }
1005 else
1006 events[event].isSelected_ =
1007 network_.isSelected(link.peerId());
1008 };
1009 auto r = rand_int(0, 1000);
1010 if (r == (int)EventType::LinkDown ||
1012 {
1013 update(static_cast<EventType>(r));
1014 }
1015 }
1016
1017 if (events[EventType::PeerDisconnected].state_ == State::On)
1018 {
1019 auto& event = events[EventType::PeerDisconnected];
1020 bool allCounting = network_.allCounting(event.peer_);
1022 event.peer_,
1023 [&](PublicKey const& v, PeerWPtr const& peerPtr) {
1024 if (event.isSelected_)
1025 sendSquelch(v, peerPtr, {});
1026 event.handled_ = true;
1027 });
1028 // Should only be unsquelched if the peer is in Selected state
1029 // If in Selected state it's possible unsquelching didn't
1030 // take place because there is no peers in Squelched state in
1031 // any of the slots where the peer is in Selected state
1032 // (allCounting is true)
1033 bool handled =
1034 (event.isSelected_ == false && !event.handled_) ||
1035 (event.isSelected_ == true &&
1036 (event.handled_ || allCounting));
1037 BEAST_EXPECT(handled);
1038 event.state_ = State::Off;
1039 event.isSelected_ = false;
1040 event.handledCnt_ += handled;
1041 event.handled_ = false;
1042 network_.onDisconnectPeer(event.peer_);
1043 }
1044
1045 auto& event = events[EventType::LinkDown];
1046 // Check every sec for idled peers. Idled peers are
1047 // created by Link Down event.
1048 if (now - lastCheck > milliseconds(1000))
1049 {
1050 lastCheck = now;
1051 // Check if Link Down event must be handled by
1052 // deleteIdlePeer(): 1) the peer is in Selected state;
1053 // 2) the peer has not received any messages for IDLED time;
1054 // 3) there are peers in Squelched state in the slot.
1055 // 4) peer is in Slot's peers_ (if not then it is deleted
1056 // by Slots::deleteIdlePeers())
1057 bool mustHandle = false;
1058 if (event.state_ == State::On && BEAST_EXPECT(event.key_))
1059 {
1060 event.isSelected_ =
1061 network_.overlay().isSelected(*event.key_, event.peer_);
1062 auto peers = network_.overlay().getPeers(*event.key_);
1063 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1064 std::get<3>(peers[event.peer_]);
1065 mustHandle = event.isSelected_ &&
1069 0 &&
1070 peers.find(event.peer_) != peers.end();
1071 }
1073 [&](PublicKey const& v, PeerWPtr const& ptr) {
1074 event.handled_ = true;
1075 if (mustHandle && v == event.key_)
1076 {
1077 event.state_ = State::WaitReset;
1078 sendSquelch(validator, ptr, {});
1079 }
1080 });
1081 bool handled =
1082 (event.handled_ && event.state_ == State::WaitReset) ||
1083 (!event.handled_ && !mustHandle);
1084 BEAST_EXPECT(handled);
1085 }
1086 if (event.state_ == State::WaitReset ||
1087 (event.state_ == State::On &&
1088 (now - event.time_ > (reduce_relay::IDLED + seconds(2)))))
1089 {
1090 bool handled =
1091 event.state_ == State::WaitReset || !event.handled_;
1092 BEAST_EXPECT(handled);
1093 event.state_ = State::Off;
1094 event.isSelected_ = false;
1095 event.handledCnt_ += handled;
1096 event.handled_ = false;
1097 network_.enableLink(event.validator_, event.peer_, true);
1098 }
1099 });
1100
1101 auto& down = events[EventType::LinkDown];
1102 auto& disconnected = events[EventType::PeerDisconnected];
1103 // It's possible the last Down Link event is not handled
1104 BEAST_EXPECT(down.handledCnt_ >= down.cnt_ - 1);
1105 // All Peer Disconnect events must be handled
1106 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1107 if (log)
1108 std::cout << "link down count: " << down.cnt_ << "/"
1109 << down.handledCnt_
1110 << " peer disconnect count: " << disconnected.cnt_ << "/"
1111 << disconnected.handledCnt_;
1112 }
1113
1114 bool
1115 checkCounting(PublicKey const& validator, bool isCountingState)
1116 {
1117 auto countingState = network_.overlay().isCountingState(validator);
1118 BEAST_EXPECT(countingState == isCountingState);
1119 return countingState == isCountingState;
1120 }
1121
1122 void
1123 doTest(const std::string& msg, bool log, std::function<void(bool)> f)
1124 {
1125 testcase(msg);
1126 f(log);
1127 }
1128
1134 void
1136 {
1137 doTest("Initial Round", log, [this](bool log) {
1138 BEAST_EXPECT(propagateAndSquelch(log));
1139 });
1140 }
1141
1145 void
1147 {
1148 doTest("Peer Unsquelched Too Soon", log, [this](bool log) {
1149 BEAST_EXPECT(propagateNoSquelch(log, 1, false, false, false));
1150 });
1151 }
1152
1156 void
1158 {
1159 ManualClock::advance(seconds(601));
1160 doTest("Peer Unsquelched", log, [this](bool log) {
1161 BEAST_EXPECT(propagateNoSquelch(log, 2, true, true, false));
1162 });
1163 }
1164
1166 bool
1167 propagateAndSquelch(bool log, bool purge = true, bool resetClock = true)
1168 {
1169 int n = 0;
1170 network_.propagate(
1171 [&](Link& link, MessageSPtr message) {
1172 std::uint16_t squelched = 0;
1173 link.send(
1174 message,
1175 [&](PublicKey const& key,
1176 PeerWPtr const& peerPtr,
1178 squelched++;
1179 sendSquelch(key, peerPtr, duration);
1180 });
1181 if (squelched)
1182 {
1183 BEAST_EXPECT(
1184 squelched ==
1186 n++;
1187 }
1188 },
1189 1,
1191 purge,
1192 resetClock);
1193 auto selected = network_.overlay().getSelected(network_.validator(0));
1194 BEAST_EXPECT(selected.size() == reduce_relay::MAX_SELECTED_PEERS);
1195 BEAST_EXPECT(n == 1); // only one selection round
1196 auto res = checkCounting(network_.validator(0), false);
1197 BEAST_EXPECT(res);
1198 return n == 1 && res;
1199 }
1200
1202 bool
1204 bool log,
1205 std::uint16_t nMessages,
1206 bool countingState,
1207 bool purge = true,
1208 bool resetClock = true)
1209 {
1210 bool squelched = false;
1211 network_.propagate(
1212 [&](Link& link, MessageSPtr message) {
1213 link.send(
1214 message,
1215 [&](PublicKey const& key,
1216 PeerWPtr const& peerPtr,
1218 squelched = true;
1219 BEAST_EXPECT(false);
1220 });
1221 },
1222 1,
1223 nMessages,
1224 purge,
1225 resetClock);
1226 auto res = checkCounting(network_.validator(0), countingState);
1227 return !squelched && res;
1228 }
1229
1233 void
1234 testNewPeer(bool log)
1235 {
1236 doTest("New Peer", log, [this](bool log) {
1237 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1238 network_.addPeer();
1239 BEAST_EXPECT(propagateNoSquelch(log, 1, true, false, false));
1240 });
1241 }
1242
1245 void
1247 {
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));
1252 std::uint16_t unsquelched = 0;
1253 network_.overlay().deletePeer(
1254 id, [&](PublicKey const& key, PeerWPtr const& peer) {
1255 unsquelched++;
1256 });
1257 BEAST_EXPECT(
1259 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1260 });
1261 }
1262
1265 void
1267 {
1268 doTest("Selected Peer Stops Relaying", log, [this](bool log) {
1269 ManualClock::advance(seconds(601));
1270 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1271 ManualClock::advance(reduce_relay::IDLED + seconds(1));
1272 std::uint16_t unsquelched = 0;
1273 network_.overlay().deleteIdlePeers(
1274 [&](PublicKey const& key, PeerWPtr const& peer) {
1275 unsquelched++;
1276 });
1277 auto peers = network_.overlay().getPeers(network_.validator(0));
1278 BEAST_EXPECT(
1280 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1281 });
1282 }
1283
1286 void
1288 {
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;
1296 });
1297 assert(it != peers.end());
1298 std::uint16_t unsquelched = 0;
1299 network_.overlay().deletePeer(
1300 it->first, [&](PublicKey const& key, PeerWPtr const& peer) {
1301 unsquelched++;
1302 });
1303 BEAST_EXPECT(unsquelched == 0);
1304 BEAST_EXPECT(checkCounting(network_.validator(0), false));
1305 });
1306 }
1307
1308 void
1309 testConfig(bool log)
1310 {
1311 doTest("Config Test", log, [&](bool log) {
1312 Config c;
1313
1314 std::string toLoad(R"rippleConfig(
1315[reduce_relay]
1316vp_enable=1
1317vp_squelch=1
1318)rippleConfig");
1319
1320 c.loadFromString(toLoad);
1321 BEAST_EXPECT(c.VP_REDUCE_RELAY_ENABLE == true);
1322 BEAST_EXPECT(c.VP_REDUCE_RELAY_SQUELCH == true);
1323
1324 Config c1;
1325
1326 toLoad = (R"rippleConfig(
1327[reduce_relay]
1328vp_enable=0
1329vp_squelch=0
1330)rippleConfig");
1331
1332 c1.loadFromString(toLoad);
1333 BEAST_EXPECT(c1.VP_REDUCE_RELAY_ENABLE == false);
1334 BEAST_EXPECT(c1.VP_REDUCE_RELAY_SQUELCH == false);
1335
1336 Config c2;
1337
1338 toLoad = R"rippleConfig(
1339[reduce_relay]
1340vp_enabled=1
1341vp_squelched=1
1342)rippleConfig";
1343
1344 c2.loadFromString(toLoad);
1345 BEAST_EXPECT(c2.VP_REDUCE_RELAY_ENABLE == false);
1346 BEAST_EXPECT(c2.VP_REDUCE_RELAY_SQUELCH == false);
1347 });
1348 }
1349
1350 void
1352 {
1353 doTest("Duplicate Message", log, [&](bool log) {
1354 network_.reset();
1355 // update message count for the same peer/validator
1356 std::int16_t nMessages = 5;
1357 for (int i = 0; i < nMessages; i++)
1358 {
1359 uint256 key(i);
1360 network_.overlay().updateSlotAndSquelch(
1361 key,
1362 network_.validator(0),
1363 0,
1364 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1365 }
1366 auto peers = network_.overlay().getPeers(network_.validator(0));
1367 // first message changes Slot state to Counting and is not counted,
1368 // hence '-1'.
1369 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1370 // add duplicate
1371 uint256 key(nMessages - 1);
1372 network_.overlay().updateSlotAndSquelch(
1373 key,
1374 network_.validator(0),
1375 0,
1376 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1377 // confirm the same number of messages
1378 peers = network_.overlay().getPeers(network_.validator(0));
1379 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1380 // advance the clock
1381 ManualClock::advance(reduce_relay::IDLED + seconds(1));
1382 network_.overlay().updateSlotAndSquelch(
1383 key,
1384 network_.validator(0),
1385 0,
1386 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1387 peers = network_.overlay().getPeers(network_.validator(0));
1388 // confirm message number increased
1389 BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
1390 });
1391 }
1392
1394 {
1395 Handler() : maxDuration_(0)
1396 {
1397 }
1398 void
1400 const override
1401 {
1402 if (duration > maxDuration_)
1403 maxDuration_ = duration;
1404 }
1405 void
1406 unsquelch(PublicKey const&, Peer::id_t) const override
1407 {
1408 }
1409 mutable int maxDuration_;
1410 };
1411
1412 void
1414 {
1415 doTest("Random Squelch", l, [&](bool l) {
1417 Handler handler;
1418
1419 auto run = [&](int npeers) {
1420 handler.maxDuration_ = 0;
1422 env_.app().logs(), handler);
1423 // 1st message from a new peer switches the slot
1424 // to counting state and resets the counts of all peers +
1425 // MAX_MESSAGE_THRESHOLD + 1 messages to reach the threshold
1426 // and switch the slot's state to peer selection.
1427 for (int m = 1; m <= reduce_relay::MAX_MESSAGE_THRESHOLD + 2;
1428 m++)
1429 {
1430 for (int peer = 0; peer < npeers; peer++)
1431 {
1432 // make unique message hash to make the
1433 // slot's internal hash router accept the message
1434 std::uint64_t mid = m * 1000 + peer;
1435 uint256 const message{mid};
1437 message,
1438 validator,
1439 peer,
1440 protocol::MessageType::mtVALIDATION);
1441 }
1442 }
1443 // make Slot's internal hash router expire all messages
1444 ManualClock::advance(hours(1));
1445 };
1446
1447 using namespace reduce_relay;
1448 // expect max duration less than MAX_UNSQUELCH_EXPIRE_DEFAULT with
1449 // less than or equal to 60 peers
1450 run(20);
1451 BEAST_EXPECT(
1452 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1453 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1454 run(60);
1455 BEAST_EXPECT(
1456 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1457 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1458 // expect max duration greater than MIN_UNSQUELCH_EXPIRE and less
1459 // than MAX_UNSQUELCH_EXPIRE_PEERS with peers greater than 60
1460 // and less than 360
1461 run(350);
1462 // can't make this condition stronger. squelch
1463 // duration is probabilistic and max condition may still fail.
1464 // log when the value is low
1465 BEAST_EXPECT(
1466 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1467 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1468 using namespace beast::unit_test::detail;
1469 if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1470 log << make_reason(
1471 "warning: squelch duration is low",
1472 __FILE__,
1473 __LINE__)
1474 << std::endl
1475 << std::flush;
1476 // more than 400 is still less than MAX_UNSQUELCH_EXPIRE_PEERS
1477 run(400);
1478 BEAST_EXPECT(
1479 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1480 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1481 if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1482 log << make_reason(
1483 "warning: squelch duration is low",
1484 __FILE__,
1485 __LINE__)
1486 << std::endl
1487 << std::flush;
1488 });
1489 }
1490
1491 void
1493 {
1494 doTest("Handshake", log, [&](bool log) {
1495 auto setEnv = [&](bool enable) {
1496 Config c;
1498 str << "[reduce_relay]\n"
1499 << "vp_enable=" << enable << "\n"
1500 << "vp_squelch=" << enable << "\n"
1501 << "[compression]\n"
1502 << "1\n";
1503 c.loadFromString(str.str());
1504 env_.app().config().VP_REDUCE_RELAY_ENABLE =
1506 env_.app().config().VP_REDUCE_RELAY_SQUELCH =
1508 env_.app().config().COMPRESSION = c.COMPRESSION;
1509 };
1510 auto handshake = [&](int outboundEnable, int inboundEnable) {
1511 beast::IP::Address addr =
1512 boost::asio::ip::address::from_string("172.1.1.100");
1513
1514 setEnv(outboundEnable);
1515 auto request = ripple::makeRequest(
1516 true,
1517 env_.app().config().COMPRESSION,
1518 false,
1519 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1520 env_.app().config().VP_REDUCE_RELAY_ENABLE);
1521 http_request_type http_request;
1522 http_request.version(request.version());
1523 http_request.base() = request.base();
1524 // feature enabled on the peer's connection only if both sides
1525 // are enabled
1526 auto const peerEnabled = inboundEnable && outboundEnable;
1527 // inbound is enabled if the request's header has the feature
1528 // enabled and the peer's configuration is enabled
1529 auto const inboundEnabled = peerFeatureEnabled(
1530 http_request, FEATURE_VPRR, inboundEnable);
1531 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1532
1533 setEnv(inboundEnable);
1534 auto http_resp = ripple::makeResponse(
1535 true,
1536 http_request,
1537 addr,
1538 addr,
1539 uint256{1},
1540 1,
1541 {1, 0},
1542 env_.app());
1543 // outbound is enabled if the response's header has the feature
1544 // enabled and the peer's configuration is enabled
1545 auto const outboundEnabled =
1546 peerFeatureEnabled(http_resp, FEATURE_VPRR, outboundEnable);
1547 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1548 };
1549 handshake(1, 1);
1550 handshake(1, 0);
1551 handshake(0, 1);
1552 handshake(0, 0);
1553 });
1554 }
1555
1558
1559public:
1560 reduce_relay_test() : env_(*this), network_(env_.app())
1561 {
1562 }
1563
1564 void
1565 run() override
1566 {
1567 bool log = false;
1568 testConfig(log);
1569 testInitialRound(log);
1570 testPeerUnsquelchedTooSoon(log);
1571 testPeerUnsquelched(log);
1572 testNewPeer(log);
1573 testSquelchedPeerDisconnects(log);
1574 testSelectedPeerDisconnects(log);
1575 testSelectedPeerStopsRelaying(log);
1576 testInternalHashRouter(log);
1577 testRandomSquelch(log);
1578 testHandshake(log);
1579 }
1580};
1581
1583{
1584 void
1585 testRandom(bool log)
1586 {
1587 doTest("Random Test", log, [&](bool log) { random(log); });
1588 }
1589
1590 void
1591 run() override
1592 {
1593 bool log = false;
1594 testRandom(log);
1595 }
1596};
1597
1598BEAST_DEFINE_TESTSUITE(reduce_relay, ripple_data, ripple);
1599BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, ripple_data, ripple);
1600
1601} // namespace test
1602
1603} // namespace ripple
T back_inserter(T... args)
T begin(T... args)
Represents a JSON value.
Definition: json_value.h:147
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
A generic endpoint for log messages.
Definition: Journal.h:59
A testsuite class.
Definition: suite.h:53
log_os< char > log
Logging output stream.
Definition: suite.h:150
bool VP_REDUCE_RELAY_ENABLE
Definition: Config.h:255
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition: Config.cpp:476
bool COMPRESSION
Definition: Config.h:227
bool VP_REDUCE_RELAY_SQUELCH
Definition: Config.h:264
Manages partitions for logging.
Definition: Log.h:49
beast::Journal journal(std::string const &name)
Definition: Log.cpp:144
Represents a peer connection in the overlay.
std::uint32_t id_t
Uniquely identifies a peer.
A public key.
Definition: PublicKey.h:62
std::uint8_t const * data() const noexcept
Definition: PublicKey.h:87
std::size_t size() const noexcept
Definition: PublicKey.h:93
A consumption charge.
Definition: Charge.h:31
An immutable linear range of bytes.
Definition: Slice.h:45
Slot is associated with a specific validator via validator's public key.
Definition: overlay/Slot.h:105
Slots is a container for validator's Slot and handles Slot update when a message is received from a v...
Definition: overlay/Slot.h:535
void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, id_t id, protocol::MessageType type)
Calls Slot::update of Slot associated with the validator.
Definition: overlay/Slot.h:700
Maintains squelching of relaying messages from validators.
Definition: Squelch.h:39
Manually advanced clock.
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 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
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.
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_
id_t id() const override
static std::uint16_t sid_
void addPeer(PeerSPtr peer)
Validator(Validator &&)=default
void send(SquelchCB f)
Send to all peers.
Validator & operator=(Validator &&)=default
void linkDown(Peer::id_t id)
void for_links(std::vector< Peer::id_t > peers, LinkIterCB f)
void deletePeer(Peer::id_t id)
void for_links(LinkIterCB f, bool simulateSlow=false)
Validator(Validator const &)=default
void send(std::vector< Peer::id_t > peers, SquelchCB f)
Send to specific peers.
void linkUp(Peer::id_t id)
Validator & operator=(Validator const &)=default
A transaction testing environment.
Definition: Env.h:117
Set the fee on a JTx.
Definition: fee.h:36
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 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 testPeerUnsquelchedTooSoon(bool log)
Receiving message from squelched peer too soon should not change the slot's state to Counting.
void testSelectedPeerDisconnects(bool log)
Selected peer disconnects.
T clear(T... args)
T emplace(T... args)
T empty(T... args)
T end(T... args)
T endl(T... args)
T erase(T... args)
T find(T... args)
T flush(T... args)
T iota(T... args)
T lock(T... args)
T make_pair(T... args)
boost::asio::ip::address Address
Definition: IPAddress.h:41
static constexpr uint16_t MAX_SELECTED_PEERS
static constexpr auto IDLED
PeerState
Peer's State.
Definition: overlay/Slot.h:49
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
Definition: envconfig.cpp:113
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.
Definition: algorithm.h:26
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.
Definition: Handshake.cpp:389
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
int run(int argc, char **argv)
Definition: Main.cpp:351
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:281
KeyType
Definition: KeyType.h:28
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition: Handoff.h:31
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:199
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
Definition: BasicConfig.h:356
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
Definition: Handshake.cpp:362
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
constexpr Number squelch(Number const &x, Number const &limit) noexcept
Definition: Number.h:363
static constexpr char FEATURE_VPRR[]
Definition: Handshake.h:144
STL namespace.
T shuffle(T... args)
T size(T... args)
T str(T... args)
Set the sequence number on a JTx.
Definition: seq.h:34
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.
T transform(T... args)