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, std::string const& context = {})
92 override
93 {
94 }
95 bool
96 cluster() const override
97 {
98 return false;
99 }
100 bool
101 isHighLatency() const override
102 {
103 return false;
104 }
105 int
106 getScore(bool) const override
107 {
108 return 0;
109 }
110 PublicKey const&
111 getNodePublic() const override
112 {
113 return nodePublicKey_;
114 }
116 json() override
117 {
118 return {};
119 }
120 bool
122 {
123 return false;
124 }
126 publisherListSequence(PublicKey const&) const override
127 {
128 return {};
129 }
130 void
132 {
133 }
134 uint256 const&
135 getClosedLedgerHash() const override
136 {
137 static uint256 hash{};
138 return hash;
139 }
140 bool
141 hasLedger(uint256 const& hash, std::uint32_t seq) const override
142 {
143 return false;
144 }
145 void
146 ledgerRange(std::uint32_t& minSeq, std::uint32_t& maxSeq) const override
147 {
148 }
149 bool
150 hasTxSet(uint256 const& hash) const override
151 {
152 return false;
153 }
154 void
155 cycleStatus() override
156 {
157 }
158 bool
160 {
161 return false;
162 }
163 bool
164 compressionEnabled() const override
165 {
166 return false;
167 }
168 bool
169 txReduceRelayEnabled() const override
170 {
171 return false;
172 }
173 void
174 sendTxQueue() override
175 {
176 }
177 void
178 addTxQueue(const uint256&) override
179 {
180 }
181 void
182 removeTxQueue(const uint256&) override
183 {
184 }
185};
186
189{
190public:
191 typedef uint64_t rep;
195 inline static const bool is_steady = false;
196
197 static void
198 advance(duration d) noexcept
199 {
200 now_ += d;
201 }
202
203 static void
205 {
206 now_ += randDuration(min, max);
207 }
208
209 static void
210 reset() noexcept
211 {
212 now_ = time_point(seconds(0));
213 }
214
215 static time_point
216 now() noexcept
217 {
218 return now_;
219 }
220
221 static duration
223 {
224 return duration(milliseconds(rand_int(min.count(), max.count())));
225 }
226
227 explicit ManualClock() = default;
228
229private:
230 inline static time_point now_ = time_point(seconds(0));
231};
232
235{
236public:
237 Overlay() = default;
238 virtual ~Overlay() = default;
239
240 virtual void
242 uint256 const& key,
243 PublicKey const& validator,
244 Peer::id_t id,
245 SquelchCB f,
246 protocol::MessageType type = protocol::mtVALIDATION) = 0;
247
248 virtual void deleteIdlePeers(UnsquelchCB) = 0;
249
251};
252
253class Validator;
254
258class Link
259{
261
262public:
265 PeerSPtr peer,
266 Latency const& latency = {milliseconds(5), milliseconds(15)})
267 : validator_(validator), peer_(peer), latency_(latency), up_(true)
268 {
269 auto sp = peer_.lock();
270 assert(sp);
271 }
272 ~Link() = default;
273 void
275 {
276 if (!up_)
277 return;
278 auto sp = peer_.lock();
279 assert(sp);
280 auto peer = std::dynamic_pointer_cast<PeerPartial>(sp);
281 peer->onMessage(m, f);
282 }
283 Validator&
285 {
286 return validator_;
287 }
288 void
289 up(bool linkUp)
290 {
291 up_ = linkUp;
292 }
295 {
296 auto p = peer_.lock();
297 assert(p);
298 return p->id();
299 }
302 {
303 auto p = peer_.lock();
304 assert(p);
305 return p;
306 }
307
308private:
312 bool up_;
313};
314
317{
319
320public:
322 {
323 protocol::TMValidation v;
324 v.set_validation("validation");
325 message_ = std::make_shared<Message>(v, protocol::mtVALIDATION, pkey_);
326 id_ = sid_++;
327 }
328 Validator(Validator const&) = default;
329 Validator(Validator&&) = default;
330 Validator&
331 operator=(Validator const&) = default;
332 Validator&
333 operator=(Validator&&) = default;
335 {
336 clear();
337 }
338
339 void
341 {
342 links_.clear();
343 }
344
345 static void
347 {
348 sid_ = 0;
349 }
350
351 PublicKey const&
353 {
354 return pkey_;
355 }
356
357 operator PublicKey() const
358 {
359 return pkey_;
360 }
361
362 void
364 {
366 std::make_pair(peer->id(), std::make_shared<Link>(*this, peer)));
367 }
368
369 void
371 {
372 links_.erase(id);
373 }
374
375 void
377 {
378 for (auto id : peers)
379 {
380 assert(links_.find(id) != links_.end());
381 f(*links_[id], message_);
382 }
383 }
384
385 void
386 for_links(LinkIterCB f, bool simulateSlow = false)
387 {
390 links_.begin(), links_.end(), std::back_inserter(v), [](auto& kv) {
391 return kv.second;
392 });
394 std::mt19937 g(d());
395 std::shuffle(v.begin(), v.end(), g);
396
397 for (auto& link : v)
398 {
399 f(*link, message_);
400 }
401 }
402
404 void
406 {
407 for_links(peers, [&](Link& link, MessageSPtr m) { link.send(m, f); });
408 }
409
411 void
413 {
414 for_links([&](Link& link, MessageSPtr m) { link.send(m, f); });
415 }
416
419 {
420 return message_;
421 }
422
425 {
426 return id_;
427 }
428
429 void
431 {
432 auto it = links_.find(id);
433 assert(it != links_.end());
434 it->second->up(true);
435 }
436
437 void
439 {
440 auto it = links_.find(id);
441 assert(it != links_.end());
442 it->second->up(false);
443 }
444
445private:
449 inline static std::uint16_t sid_ = 0;
451};
452
453class PeerSim : public PeerPartial, public std::enable_shared_from_this<PeerSim>
454{
455public:
457 PeerSim(Overlay& overlay, beast::Journal journal)
458 : overlay_(overlay), squelch_(journal)
459 {
460 id_ = sid_++;
461 }
462
463 ~PeerSim() = default;
464
465 id_t
466 id() const override
467 {
468 return id_;
469 }
470
471 static void
473 {
474 sid_ = 0;
475 }
476
478 void
479 onMessage(MessageSPtr const& m, SquelchCB f) override
480 {
481 auto validator = m->getValidatorKey();
482 assert(validator);
483 if (!squelch_.expireSquelch(*validator))
484 return;
485
487 }
488
490 virtual void
491 onMessage(protocol::TMSquelch const& squelch) override
492 {
493 auto validator = squelch.validatorpubkey();
494 PublicKey key(Slice(validator.data(), validator.size()));
495 if (squelch.squelch())
496 squelch_.addSquelch(
497 key, std::chrono::seconds{squelch.squelchduration()});
498 else
499 squelch_.removeSquelch(key);
500 }
501
502private:
503 inline static id_t sid_ = 0;
507};
508
510{
512
513public:
516 OverlaySim(Application& app) : slots_(app.logs(), *this), logs_(app.logs())
517 {
518 }
519
520 ~OverlaySim() = default;
521
522 void
524 {
525 peers_.clear();
527 slots_.deleteIdlePeers();
528 }
529
532 {
533 auto res = slots_.inState(validator, state);
534 return res ? *res : 0;
535 }
536
537 void
539 uint256 const& key,
540 PublicKey const& validator,
541 Peer::id_t id,
542 SquelchCB f,
543 protocol::MessageType type = protocol::mtVALIDATION) override
544 {
545 squelch_ = f;
546 slots_.updateSlotAndSquelch(key, validator, id, type);
547 }
548
549 void
551 {
552 unsquelch_ = f;
553 slots_.deletePeer(id, true);
554 }
555
556 void
558 {
559 unsquelch_ = f;
560 slots_.deleteIdlePeers();
561 }
562
564 addPeer(bool useCache = true)
565 {
566 PeerSPtr peer{};
567 Peer::id_t id;
568 if (peersCache_.empty() || !useCache)
569 {
570 peer = std::make_shared<PeerSim>(*this, logs_.journal("Squelch"));
571 id = peer->id();
572 }
573 else
574 {
575 auto it = peersCache_.begin();
576 peer = it->second;
577 id = it->first;
578 peersCache_.erase(it);
579 }
580 peers_.emplace(std::make_pair(id, peer));
581 return peer;
582 }
583
584 void
585 deletePeer(Peer::id_t id, bool useCache = true)
586 {
587 auto it = peers_.find(id);
588 assert(it != peers_.end());
589 deletePeer(id, [&](PublicKey const&, PeerWPtr) {});
590 if (useCache)
591 peersCache_.emplace(std::make_pair(id, it->second));
592 peers_.erase(it);
593 }
594
595 void
597 {
598 while (!peers_.empty())
599 deletePeer(peers_.begin()->first);
600 while (!peersCache_.empty())
601 addPeer();
602 }
603
606 {
607 if (peers_.empty())
608 return {};
609
610 std::uint8_t maxId = 0;
611
612 for (auto& [id, _] : peers_)
613 {
614 (void)_;
615 if (id > maxId)
616 maxId = id;
617 }
618
619 deletePeer(maxId, false);
620
621 return maxId;
622 }
623
624 bool
626 {
628 }
629
632 {
633 return slots_.getSelected(validator);
634 }
635
636 bool
638 {
639 auto selected = slots_.getSelected(validator);
640 return selected.find(peer) != selected.end();
641 }
642
643 id_t
645 {
646 auto selected = slots_.getSelected(validator);
647 assert(selected.size());
648 return *selected.begin();
649 }
650
652 id_t,
659 {
660 return slots_.getPeers(validator);
661 }
662
665 {
666 return peers_.size();
667 }
668
669private:
670 void
672 PublicKey const& validator,
673 Peer::id_t id,
674 std::uint32_t squelchDuration) const override
675 {
676 if (auto it = peers_.find(id); it != peers_.end())
677 squelch_(validator, it->second, squelchDuration);
678 }
679 void
680 unsquelch(PublicKey const& validator, Peer::id_t id) const override
681 {
682 if (auto it = peers_.find(id); it != peers_.end())
683 unsquelch_(validator, it->second);
684 }
691};
692
694{
695public:
697 {
698 init();
699 }
700
701 void
703 {
705 for (int p = 0; p < MAX_PEERS; p++)
706 {
707 auto peer = overlay_.addPeer();
708 for (auto& v : validators_)
709 v.addPeer(peer);
710 }
711 }
712
713 ~Network() = default;
714
715 void
717 {
718 validators_.clear();
719 overlay_.clear();
722 init();
723 }
724
727 {
728 auto peer = overlay_.addPeer();
729 for (auto& v : validators_)
730 v.addPeer(peer);
731 return peer->id();
732 }
733
734 void
736 {
737 auto id = overlay_.deleteLastPeer();
738
739 if (!id)
740 return;
741
742 for (auto& validator : validators_)
744 }
745
746 void
748 {
749 while (overlay_.getNumPeers() > MAX_PEERS)
751 }
752
753 Validator&
755 {
756 assert(v < validators_.size());
757 return validators_[v];
758 }
759
762 {
763 return overlay_;
764 }
765
766 void
767 enableLink(std::uint16_t validatorId, Peer::id_t peer, bool enable)
768 {
769 auto it =
770 std::find_if(validators_.begin(), validators_.end(), [&](auto& v) {
771 return v.id() == validatorId;
772 });
773 assert(it != validators_.end());
774 if (enable)
775 it->linkUp(peer);
776 else
777 it->linkDown(peer);
778 }
779
780 void
782 {
783 // Send unsquelch to the Peer on all links. This way when
784 // the Peer "reconnects" it starts sending messages on the link.
785 // We expect that if a Peer disconnects and then reconnects, it's
786 // unsquelched.
787 protocol::TMSquelch squelch;
788 squelch.set_squelch(false);
789 for (auto& v : validators_)
790 {
791 PublicKey key = v;
792 squelch.clear_validatorpubkey();
793 squelch.set_validatorpubkey(key.data(), key.size());
794 v.for_links({peer}, [&](Link& l, MessageSPtr) {
795 std::dynamic_pointer_cast<PeerSim>(l.getPeer())->send(squelch);
796 });
797 }
798 }
799
800 void
802 std::uint32_t min,
803 std::uint32_t max,
805 {
806 auto size = max - min;
808 std::iota(s.begin(), s.end(), min);
810 std::mt19937 g(d());
811 std::shuffle(s.begin(), s.end(), g);
812 for (auto v : s)
813 f(v);
814 }
815
816 void
818 LinkIterCB link,
819 std::uint16_t nValidators = MAX_VALIDATORS,
820 std::uint32_t nMessages = MAX_MESSAGES,
821 bool purge = true,
822 bool resetClock = true)
823 {
824 if (resetClock)
826
827 if (purge)
828 {
829 purgePeers();
831 }
832
833 for (int m = 0; m < nMessages; ++m)
834 {
836 for_rand(0, nValidators, [&](std::uint32_t v) {
837 validators_[v].for_links(link);
838 });
839 }
840 }
841
843 bool
845 {
846 for (auto& v : validators_)
847 {
848 if (overlay_.isSelected(v, id))
849 return true;
850 }
851 return false;
852 }
853
858 bool
860 {
861 for (auto& v : validators_)
862 {
863 if (!overlay_.isSelected(v, peer))
864 continue;
865 auto peers = overlay_.getPeers(v);
866 for (auto& [_, v] : peers)
867 {
868 (void)_;
869 if (std::get<reduce_relay::PeerState>(v) ==
871 return false;
872 }
873 }
874 return true;
875 }
876
877private:
880};
881
883{
886
887protected:
888 void
890 {
892 std::cout << msg << " " << "num peers "
893 << (int)network_.overlay().getNumPeers() << std::endl;
894 for (auto& [k, v] : peers)
895 std::cout << k << ":" << (int)std::get<reduce_relay::PeerState>(v)
896 << " ";
898 }
899
903 PublicKey const& validator,
904 PeerWPtr const& peerPtr,
906 {
907 protocol::TMSquelch squelch;
908 bool res = duration ? true : false;
909 squelch.set_squelch(res);
910 squelch.set_validatorpubkey(validator.data(), validator.size());
911 if (res)
912 squelch.set_squelchduration(*duration);
913 auto sp = peerPtr.lock();
914 assert(sp);
915 std::dynamic_pointer_cast<PeerSim>(sp)->send(squelch);
916 return sp->id();
917 }
918
919 enum State { On, Off, WaitReset };
921 // Link down or Peer disconnect event
922 // TBD - add new peer event
923 // TBD - add overlapping type of events at any
924 // time in any quantity
925 struct Event
926 {
930 bool isSelected_ = false;
935 bool handled_ = false;
936 };
937
941 void
943 {
945 {LinkDown, {}}, {PeerDisconnected, {}}};
947
948 network_.reset();
949 network_.propagate([&](Link& link, MessageSPtr m) {
950 auto& validator = link.validator();
951 auto now = ManualClock::now();
952
953 bool squelched = false;
955
956 link.send(
957 m,
958 [&](PublicKey const& key,
959 PeerWPtr const& peerPtr,
961 assert(key == validator);
962 auto p = sendSquelch(key, peerPtr, duration);
963 squelched = true;
964 str << p << " ";
965 });
966
967 if (squelched)
968 {
969 auto selected = network_.overlay().getSelected(validator);
970 str << " selected: ";
971 for (auto s : selected)
972 str << s << " ";
973 if (log)
975 << (double)reduce_relay::epoch<milliseconds>(now)
976 .count() /
977 1000.
978 << " random, squelched, validator: " << validator.id()
979 << " peers: " << str.str() << std::endl;
980 auto countingState =
982 BEAST_EXPECT(
983 countingState == false &&
984 selected.size() == reduce_relay::MAX_SELECTED_PEERS);
985 }
986
987 // Trigger Link Down or Peer Disconnect event
988 // Only one Link Down at a time
989 if (events[EventType::LinkDown].state_ == State::Off)
990 {
991 auto update = [&](EventType event) {
992 events[event].cnt_++;
993 events[event].validator_ = validator.id();
994 events[event].key_ = validator;
995 events[event].peer_ = link.peerId();
996 events[event].state_ = State::On;
997 events[event].time_ = now;
998 if (event == EventType::LinkDown)
999 {
1001 validator.id(), link.peerId(), false);
1002 events[event].isSelected_ =
1004 validator, link.peerId());
1005 }
1006 else
1007 events[event].isSelected_ =
1008 network_.isSelected(link.peerId());
1009 };
1010 auto r = rand_int(0, 1000);
1011 if (r == (int)EventType::LinkDown ||
1013 {
1014 update(static_cast<EventType>(r));
1015 }
1016 }
1017
1018 if (events[EventType::PeerDisconnected].state_ == State::On)
1019 {
1020 auto& event = events[EventType::PeerDisconnected];
1021 bool allCounting = network_.allCounting(event.peer_);
1023 event.peer_,
1024 [&](PublicKey const& v, PeerWPtr const& peerPtr) {
1025 if (event.isSelected_)
1026 sendSquelch(v, peerPtr, {});
1027 event.handled_ = true;
1028 });
1029 // Should only be unsquelched if the peer is in Selected state
1030 // If in Selected state it's possible unsquelching didn't
1031 // take place because there is no peers in Squelched state in
1032 // any of the slots where the peer is in Selected state
1033 // (allCounting is true)
1034 bool handled =
1035 (event.isSelected_ == false && !event.handled_) ||
1036 (event.isSelected_ == true &&
1037 (event.handled_ || allCounting));
1038 BEAST_EXPECT(handled);
1039 event.state_ = State::Off;
1040 event.isSelected_ = false;
1041 event.handledCnt_ += handled;
1042 event.handled_ = false;
1043 network_.onDisconnectPeer(event.peer_);
1044 }
1045
1046 auto& event = events[EventType::LinkDown];
1047 // Check every sec for idled peers. Idled peers are
1048 // created by Link Down event.
1049 if (now - lastCheck > milliseconds(1000))
1050 {
1051 lastCheck = now;
1052 // Check if Link Down event must be handled by
1053 // deleteIdlePeer(): 1) the peer is in Selected state;
1054 // 2) the peer has not received any messages for IDLED time;
1055 // 3) there are peers in Squelched state in the slot.
1056 // 4) peer is in Slot's peers_ (if not then it is deleted
1057 // by Slots::deleteIdlePeers())
1058 bool mustHandle = false;
1059 if (event.state_ == State::On && BEAST_EXPECT(event.key_))
1060 {
1061 event.isSelected_ =
1062 network_.overlay().isSelected(*event.key_, event.peer_);
1063 auto peers = network_.overlay().getPeers(*event.key_);
1064 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1065 std::get<3>(peers[event.peer_]);
1066 mustHandle = event.isSelected_ &&
1070 0 &&
1071 peers.find(event.peer_) != peers.end();
1072 }
1074 [&](PublicKey const& v, PeerWPtr const& ptr) {
1075 event.handled_ = true;
1076 if (mustHandle && v == event.key_)
1077 {
1078 event.state_ = State::WaitReset;
1079 sendSquelch(validator, ptr, {});
1080 }
1081 });
1082 bool handled =
1083 (event.handled_ && event.state_ == State::WaitReset) ||
1084 (!event.handled_ && !mustHandle);
1085 BEAST_EXPECT(handled);
1086 }
1087 if (event.state_ == State::WaitReset ||
1088 (event.state_ == State::On &&
1089 (now - event.time_ > (reduce_relay::IDLED + seconds(2)))))
1090 {
1091 bool handled =
1092 event.state_ == State::WaitReset || !event.handled_;
1093 BEAST_EXPECT(handled);
1094 event.state_ = State::Off;
1095 event.isSelected_ = false;
1096 event.handledCnt_ += handled;
1097 event.handled_ = false;
1098 network_.enableLink(event.validator_, event.peer_, true);
1099 }
1100 });
1101
1102 auto& down = events[EventType::LinkDown];
1103 auto& disconnected = events[EventType::PeerDisconnected];
1104 // It's possible the last Down Link event is not handled
1105 BEAST_EXPECT(down.handledCnt_ >= down.cnt_ - 1);
1106 // All Peer Disconnect events must be handled
1107 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1108 if (log)
1109 std::cout << "link down count: " << down.cnt_ << "/"
1110 << down.handledCnt_
1111 << " peer disconnect count: " << disconnected.cnt_ << "/"
1112 << disconnected.handledCnt_;
1113 }
1114
1115 bool
1116 checkCounting(PublicKey const& validator, bool isCountingState)
1117 {
1118 auto countingState = network_.overlay().isCountingState(validator);
1119 BEAST_EXPECT(countingState == isCountingState);
1120 return countingState == isCountingState;
1121 }
1122
1123 void
1124 doTest(const std::string& msg, bool log, std::function<void(bool)> f)
1125 {
1126 testcase(msg);
1127 f(log);
1128 }
1129
1135 void
1137 {
1138 doTest("Initial Round", log, [this](bool log) {
1139 BEAST_EXPECT(propagateAndSquelch(log));
1140 });
1141 }
1142
1146 void
1148 {
1149 doTest("Peer Unsquelched Too Soon", log, [this](bool log) {
1150 BEAST_EXPECT(propagateNoSquelch(log, 1, false, false, false));
1151 });
1152 }
1153
1157 void
1159 {
1160 ManualClock::advance(seconds(601));
1161 doTest("Peer Unsquelched", log, [this](bool log) {
1162 BEAST_EXPECT(propagateNoSquelch(log, 2, true, true, false));
1163 });
1164 }
1165
1167 bool
1168 propagateAndSquelch(bool log, bool purge = true, bool resetClock = true)
1169 {
1170 int n = 0;
1171 network_.propagate(
1172 [&](Link& link, MessageSPtr message) {
1173 std::uint16_t squelched = 0;
1174 link.send(
1175 message,
1176 [&](PublicKey const& key,
1177 PeerWPtr const& peerPtr,
1179 squelched++;
1180 sendSquelch(key, peerPtr, duration);
1181 });
1182 if (squelched)
1183 {
1184 BEAST_EXPECT(
1185 squelched ==
1187 n++;
1188 }
1189 },
1190 1,
1192 purge,
1193 resetClock);
1194 auto selected = network_.overlay().getSelected(network_.validator(0));
1195 BEAST_EXPECT(selected.size() == reduce_relay::MAX_SELECTED_PEERS);
1196 BEAST_EXPECT(n == 1); // only one selection round
1197 auto res = checkCounting(network_.validator(0), false);
1198 BEAST_EXPECT(res);
1199 return n == 1 && res;
1200 }
1201
1203 bool
1205 bool log,
1206 std::uint16_t nMessages,
1207 bool countingState,
1208 bool purge = true,
1209 bool resetClock = true)
1210 {
1211 bool squelched = false;
1212 network_.propagate(
1213 [&](Link& link, MessageSPtr message) {
1214 link.send(
1215 message,
1216 [&](PublicKey const& key,
1217 PeerWPtr const& peerPtr,
1219 squelched = true;
1220 BEAST_EXPECT(false);
1221 });
1222 },
1223 1,
1224 nMessages,
1225 purge,
1226 resetClock);
1227 auto res = checkCounting(network_.validator(0), countingState);
1228 return !squelched && res;
1229 }
1230
1234 void
1235 testNewPeer(bool log)
1236 {
1237 doTest("New Peer", log, [this](bool log) {
1238 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1239 network_.addPeer();
1240 BEAST_EXPECT(propagateNoSquelch(log, 1, true, false, false));
1241 });
1242 }
1243
1246 void
1248 {
1249 doTest("Selected Peer Disconnects", log, [this](bool log) {
1250 ManualClock::advance(seconds(601));
1251 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1252 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1253 std::uint16_t unsquelched = 0;
1254 network_.overlay().deletePeer(
1255 id, [&](PublicKey const& key, PeerWPtr const& peer) {
1256 unsquelched++;
1257 });
1258 BEAST_EXPECT(
1260 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1261 });
1262 }
1263
1266 void
1268 {
1269 doTest("Selected Peer Stops Relaying", log, [this](bool log) {
1270 ManualClock::advance(seconds(601));
1271 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1272 ManualClock::advance(reduce_relay::IDLED + seconds(1));
1273 std::uint16_t unsquelched = 0;
1274 network_.overlay().deleteIdlePeers(
1275 [&](PublicKey const& key, PeerWPtr const& peer) {
1276 unsquelched++;
1277 });
1278 auto peers = network_.overlay().getPeers(network_.validator(0));
1279 BEAST_EXPECT(
1281 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1282 });
1283 }
1284
1287 void
1289 {
1290 doTest("Squelched Peer Disconnects", log, [this](bool log) {
1291 ManualClock::advance(seconds(601));
1292 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1293 auto peers = network_.overlay().getPeers(network_.validator(0));
1294 auto it = std::find_if(peers.begin(), peers.end(), [&](auto it) {
1295 return std::get<reduce_relay::PeerState>(it.second) ==
1296 reduce_relay::PeerState::Squelched;
1297 });
1298 assert(it != peers.end());
1299 std::uint16_t unsquelched = 0;
1300 network_.overlay().deletePeer(
1301 it->first, [&](PublicKey const& key, PeerWPtr const& peer) {
1302 unsquelched++;
1303 });
1304 BEAST_EXPECT(unsquelched == 0);
1305 BEAST_EXPECT(checkCounting(network_.validator(0), false));
1306 });
1307 }
1308
1309 void
1310 testConfig(bool log)
1311 {
1312 doTest("Config Test", log, [&](bool log) {
1313 Config c;
1314
1315 std::string toLoad(R"rippleConfig(
1316[reduce_relay]
1317vp_enable=1
1318vp_squelch=1
1319)rippleConfig");
1320
1321 c.loadFromString(toLoad);
1322 BEAST_EXPECT(c.VP_REDUCE_RELAY_ENABLE == true);
1323 BEAST_EXPECT(c.VP_REDUCE_RELAY_SQUELCH == true);
1324
1325 Config c1;
1326
1327 toLoad = (R"rippleConfig(
1328[reduce_relay]
1329vp_enable=0
1330vp_squelch=0
1331)rippleConfig");
1332
1333 c1.loadFromString(toLoad);
1334 BEAST_EXPECT(c1.VP_REDUCE_RELAY_ENABLE == false);
1335 BEAST_EXPECT(c1.VP_REDUCE_RELAY_SQUELCH == false);
1336
1337 Config c2;
1338
1339 toLoad = R"rippleConfig(
1340[reduce_relay]
1341vp_enabled=1
1342vp_squelched=1
1343)rippleConfig";
1344
1345 c2.loadFromString(toLoad);
1346 BEAST_EXPECT(c2.VP_REDUCE_RELAY_ENABLE == false);
1347 BEAST_EXPECT(c2.VP_REDUCE_RELAY_SQUELCH == false);
1348 });
1349 }
1350
1351 void
1353 {
1354 doTest("Duplicate Message", log, [&](bool log) {
1355 network_.reset();
1356 // update message count for the same peer/validator
1357 std::int16_t nMessages = 5;
1358 for (int i = 0; i < nMessages; i++)
1359 {
1360 uint256 key(i);
1361 network_.overlay().updateSlotAndSquelch(
1362 key,
1363 network_.validator(0),
1364 0,
1365 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1366 }
1367 auto peers = network_.overlay().getPeers(network_.validator(0));
1368 // first message changes Slot state to Counting and is not counted,
1369 // hence '-1'.
1370 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1371 // add duplicate
1372 uint256 key(nMessages - 1);
1373 network_.overlay().updateSlotAndSquelch(
1374 key,
1375 network_.validator(0),
1376 0,
1377 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1378 // confirm the same number of messages
1379 peers = network_.overlay().getPeers(network_.validator(0));
1380 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1381 // advance the clock
1382 ManualClock::advance(reduce_relay::IDLED + seconds(1));
1383 network_.overlay().updateSlotAndSquelch(
1384 key,
1385 network_.validator(0),
1386 0,
1387 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1388 peers = network_.overlay().getPeers(network_.validator(0));
1389 // confirm message number increased
1390 BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
1391 });
1392 }
1393
1395 {
1396 Handler() : maxDuration_(0)
1397 {
1398 }
1399 void
1401 const override
1402 {
1403 if (duration > maxDuration_)
1404 maxDuration_ = duration;
1405 }
1406 void
1407 unsquelch(PublicKey const&, Peer::id_t) const override
1408 {
1409 }
1410 mutable int maxDuration_;
1411 };
1412
1413 void
1415 {
1416 doTest("Random Squelch", l, [&](bool l) {
1418 Handler handler;
1419
1420 auto run = [&](int npeers) {
1421 handler.maxDuration_ = 0;
1423 env_.app().logs(), handler);
1424 // 1st message from a new peer switches the slot
1425 // to counting state and resets the counts of all peers +
1426 // MAX_MESSAGE_THRESHOLD + 1 messages to reach the threshold
1427 // and switch the slot's state to peer selection.
1428 for (int m = 1; m <= reduce_relay::MAX_MESSAGE_THRESHOLD + 2;
1429 m++)
1430 {
1431 for (int peer = 0; peer < npeers; peer++)
1432 {
1433 // make unique message hash to make the
1434 // slot's internal hash router accept the message
1435 std::uint64_t mid = m * 1000 + peer;
1436 uint256 const message{mid};
1438 message,
1439 validator,
1440 peer,
1441 protocol::MessageType::mtVALIDATION);
1442 }
1443 }
1444 // make Slot's internal hash router expire all messages
1445 ManualClock::advance(hours(1));
1446 };
1447
1448 using namespace reduce_relay;
1449 // expect max duration less than MAX_UNSQUELCH_EXPIRE_DEFAULT with
1450 // less than or equal to 60 peers
1451 run(20);
1452 BEAST_EXPECT(
1453 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1454 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1455 run(60);
1456 BEAST_EXPECT(
1457 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1458 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1459 // expect max duration greater than MIN_UNSQUELCH_EXPIRE and less
1460 // than MAX_UNSQUELCH_EXPIRE_PEERS with peers greater than 60
1461 // and less than 360
1462 run(350);
1463 // can't make this condition stronger. squelch
1464 // duration is probabilistic and max condition may still fail.
1465 // log when the value is low
1466 BEAST_EXPECT(
1467 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1468 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1469 using namespace beast::unit_test::detail;
1470 if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1471 log << make_reason(
1472 "warning: squelch duration is low",
1473 __FILE__,
1474 __LINE__)
1475 << std::endl
1476 << std::flush;
1477 // more than 400 is still less than MAX_UNSQUELCH_EXPIRE_PEERS
1478 run(400);
1479 BEAST_EXPECT(
1480 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1481 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1482 if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1483 log << make_reason(
1484 "warning: squelch duration is low",
1485 __FILE__,
1486 __LINE__)
1487 << std::endl
1488 << std::flush;
1489 });
1490 }
1491
1492 void
1494 {
1495 doTest("Handshake", log, [&](bool log) {
1496 auto setEnv = [&](bool enable) {
1497 Config c;
1499 str << "[reduce_relay]\n"
1500 << "vp_enable=" << enable << "\n"
1501 << "vp_squelch=" << enable << "\n"
1502 << "[compression]\n"
1503 << "1\n";
1504 c.loadFromString(str.str());
1505 env_.app().config().VP_REDUCE_RELAY_ENABLE =
1507 env_.app().config().VP_REDUCE_RELAY_SQUELCH =
1509 env_.app().config().COMPRESSION = c.COMPRESSION;
1510 };
1511 auto handshake = [&](int outboundEnable, int inboundEnable) {
1512 beast::IP::Address addr =
1513 boost::asio::ip::address::from_string("172.1.1.100");
1514
1515 setEnv(outboundEnable);
1516 auto request = ripple::makeRequest(
1517 true,
1518 env_.app().config().COMPRESSION,
1519 false,
1520 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1521 env_.app().config().VP_REDUCE_RELAY_ENABLE);
1522 http_request_type http_request;
1523 http_request.version(request.version());
1524 http_request.base() = request.base();
1525 // feature enabled on the peer's connection only if both sides
1526 // are enabled
1527 auto const peerEnabled = inboundEnable && outboundEnable;
1528 // inbound is enabled if the request's header has the feature
1529 // enabled and the peer's configuration is enabled
1530 auto const inboundEnabled = peerFeatureEnabled(
1531 http_request, FEATURE_VPRR, inboundEnable);
1532 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1533
1534 setEnv(inboundEnable);
1535 auto http_resp = ripple::makeResponse(
1536 true,
1537 http_request,
1538 addr,
1539 addr,
1540 uint256{1},
1541 1,
1542 {1, 0},
1543 env_.app());
1544 // outbound is enabled if the response's header has the feature
1545 // enabled and the peer's configuration is enabled
1546 auto const outboundEnabled =
1547 peerFeatureEnabled(http_resp, FEATURE_VPRR, outboundEnable);
1548 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1549 };
1550 handshake(1, 1);
1551 handshake(1, 0);
1552 handshake(0, 1);
1553 handshake(0, 0);
1554 });
1555 }
1556
1559
1560public:
1561 reduce_relay_test() : env_(*this), network_(env_.app())
1562 {
1563 }
1564
1565 void
1566 run() override
1567 {
1568 bool log = false;
1569 testConfig(log);
1570 testInitialRound(log);
1571 testPeerUnsquelchedTooSoon(log);
1572 testPeerUnsquelched(log);
1573 testNewPeer(log);
1574 testSquelchedPeerDisconnects(log);
1575 testSelectedPeerDisconnects(log);
1576 testSelectedPeerStopsRelaying(log);
1577 testInternalHashRouter(log);
1578 testRandomSquelch(log);
1579 testHandshake(log);
1580 }
1581};
1582
1584{
1585 void
1586 testRandom(bool log)
1587 {
1588 doTest("Random Test", log, [&](bool log) { random(log); });
1589 }
1590
1591 void
1592 run() override
1593 {
1594 bool log = false;
1595 testRandom(log);
1596 }
1597};
1598
1599BEAST_DEFINE_TESTSUITE(reduce_relay, ripple_data, ripple);
1600BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, ripple_data, ripple);
1601
1602} // namespace test
1603
1604} // 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
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.
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)