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 }
186 releaseRequestCookies(uint256 const& requestHash) override
187 {
188 return {};
189 }
190};
191
194{
195public:
196 typedef uint64_t rep;
200 inline static const bool is_steady = false;
201
202 static void
203 advance(duration d) noexcept
204 {
205 now_ += d;
206 }
207
208 static void
210 {
211 now_ += randDuration(min, max);
212 }
213
214 static void
215 reset() noexcept
216 {
217 now_ = time_point(seconds(0));
218 }
219
220 static time_point
221 now() noexcept
222 {
223 return now_;
224 }
225
226 static duration
228 {
229 return duration(milliseconds(rand_int(min.count(), max.count())));
230 }
231
232 explicit ManualClock() = default;
233
234private:
235 inline static time_point now_ = time_point(seconds(0));
236};
237
240{
241public:
242 Overlay() = default;
243 virtual ~Overlay() = default;
244
245 virtual void
247 uint256 const& key,
248 PublicKey const& validator,
249 Peer::id_t id,
250 SquelchCB f,
251 protocol::MessageType type = protocol::mtVALIDATION) = 0;
252
253 virtual void deleteIdlePeers(UnsquelchCB) = 0;
254
256};
257
258class Validator;
259
263class Link
264{
266
267public:
270 PeerSPtr peer,
271 Latency const& latency = {milliseconds(5), milliseconds(15)})
272 : validator_(validator), peer_(peer), latency_(latency), up_(true)
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);
285 auto peer = std::dynamic_pointer_cast<PeerPartial>(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_;
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 {
371 std::make_pair(peer->id(), std::make_shared<Link>(*this, peer)));
372 }
373
374 void
376 {
377 links_.erase(id);
378 }
379
380 void
382 {
383 for (auto id : peers)
384 {
385 assert(links_.find(id) != links_.end());
386 f(*links_[id], message_);
387 }
388 }
389
390 void
391 for_links(LinkIterCB f, bool simulateSlow = false)
392 {
395 links_.begin(), links_.end(), std::back_inserter(v), [](auto& kv) {
396 return kv.second;
397 });
399 std::mt19937 g(d());
400 std::shuffle(v.begin(), v.end(), g);
401
402 for (auto& link : v)
403 {
404 f(*link, message_);
405 }
406 }
407
409 void
411 {
412 for_links(peers, [&](Link& link, MessageSPtr m) { link.send(m, f); });
413 }
414
416 void
418 {
419 for_links([&](Link& link, MessageSPtr m) { link.send(m, f); });
420 }
421
424 {
425 return message_;
426 }
427
430 {
431 return id_;
432 }
433
434 void
436 {
437 auto it = links_.find(id);
438 assert(it != links_.end());
439 it->second->up(true);
440 }
441
442 void
444 {
445 auto it = links_.find(id);
446 assert(it != links_.end());
447 it->second->up(false);
448 }
449
450private:
454 inline static std::uint16_t sid_ = 0;
456};
457
458class PeerSim : public PeerPartial, public std::enable_shared_from_this<PeerSim>
459{
460public:
462 PeerSim(Overlay& overlay, beast::Journal journal)
463 : overlay_(overlay), squelch_(journal)
464 {
465 id_ = sid_++;
466 }
467
468 ~PeerSim() = default;
469
470 id_t
471 id() const override
472 {
473 return id_;
474 }
475
476 static void
478 {
479 sid_ = 0;
480 }
481
483 void
484 onMessage(MessageSPtr const& m, SquelchCB f) override
485 {
486 auto validator = m->getValidatorKey();
487 assert(validator);
488 if (!squelch_.expireSquelch(*validator))
489 return;
490
492 }
493
495 virtual void
496 onMessage(protocol::TMSquelch const& squelch) override
497 {
498 auto validator = squelch.validatorpubkey();
499 PublicKey key(Slice(validator.data(), validator.size()));
500 if (squelch.squelch())
501 squelch_.addSquelch(
502 key, std::chrono::seconds{squelch.squelchduration()});
503 else
504 squelch_.removeSquelch(key);
505 }
506
507private:
508 inline static id_t sid_ = 0;
512};
513
515{
517
518public:
521 OverlaySim(Application& app) : slots_(app.logs(), *this), logs_(app.logs())
522 {
523 }
524
525 ~OverlaySim() = default;
526
527 void
529 {
530 peers_.clear();
532 slots_.deleteIdlePeers();
533 }
534
537 {
538 auto res = slots_.inState(validator, state);
539 return res ? *res : 0;
540 }
541
542 void
544 uint256 const& key,
545 PublicKey const& validator,
546 Peer::id_t id,
547 SquelchCB f,
548 protocol::MessageType type = protocol::mtVALIDATION) override
549 {
550 squelch_ = f;
551 slots_.updateSlotAndSquelch(key, validator, id, type);
552 }
553
554 void
556 {
557 unsquelch_ = f;
558 slots_.deletePeer(id, true);
559 }
560
561 void
563 {
564 unsquelch_ = f;
565 slots_.deleteIdlePeers();
566 }
567
569 addPeer(bool useCache = true)
570 {
571 PeerSPtr peer{};
572 Peer::id_t id;
573 if (peersCache_.empty() || !useCache)
574 {
575 peer = std::make_shared<PeerSim>(*this, logs_.journal("Squelch"));
576 id = peer->id();
577 }
578 else
579 {
580 auto it = peersCache_.begin();
581 peer = it->second;
582 id = it->first;
583 peersCache_.erase(it);
584 }
585 peers_.emplace(std::make_pair(id, peer));
586 return peer;
587 }
588
589 void
590 deletePeer(Peer::id_t id, bool useCache = true)
591 {
592 auto it = peers_.find(id);
593 assert(it != peers_.end());
594 deletePeer(id, [&](PublicKey const&, PeerWPtr) {});
595 if (useCache)
596 peersCache_.emplace(std::make_pair(id, it->second));
597 peers_.erase(it);
598 }
599
600 void
602 {
603 while (!peers_.empty())
604 deletePeer(peers_.begin()->first);
605 while (!peersCache_.empty())
606 addPeer();
607 }
608
611 {
612 if (peers_.empty())
613 return {};
614
615 std::uint8_t maxId = 0;
616
617 for (auto& [id, _] : peers_)
618 {
619 (void)_;
620 if (id > maxId)
621 maxId = id;
622 }
623
624 deletePeer(maxId, false);
625
626 return maxId;
627 }
628
629 bool
631 {
633 }
634
637 {
638 return slots_.getSelected(validator);
639 }
640
641 bool
643 {
644 auto selected = slots_.getSelected(validator);
645 return selected.find(peer) != selected.end();
646 }
647
648 id_t
650 {
651 auto selected = slots_.getSelected(validator);
652 assert(selected.size());
653 return *selected.begin();
654 }
655
657 id_t,
664 {
665 return slots_.getPeers(validator);
666 }
667
670 {
671 return peers_.size();
672 }
673
674private:
675 void
677 PublicKey const& validator,
678 Peer::id_t id,
679 std::uint32_t squelchDuration) const override
680 {
681 if (auto it = peers_.find(id); it != peers_.end())
682 squelch_(validator, it->second, squelchDuration);
683 }
684 void
685 unsquelch(PublicKey const& validator, Peer::id_t id) const override
686 {
687 if (auto it = peers_.find(id); it != peers_.end())
688 unsquelch_(validator, it->second);
689 }
696};
697
699{
700public:
702 {
703 init();
704 }
705
706 void
708 {
710 for (int p = 0; p < MAX_PEERS; p++)
711 {
712 auto peer = overlay_.addPeer();
713 for (auto& v : validators_)
714 v.addPeer(peer);
715 }
716 }
717
718 ~Network() = default;
719
720 void
722 {
723 validators_.clear();
724 overlay_.clear();
727 init();
728 }
729
732 {
733 auto peer = overlay_.addPeer();
734 for (auto& v : validators_)
735 v.addPeer(peer);
736 return peer->id();
737 }
738
739 void
741 {
742 auto id = overlay_.deleteLastPeer();
743
744 if (!id)
745 return;
746
747 for (auto& validator : validators_)
749 }
750
751 void
753 {
754 while (overlay_.getNumPeers() > MAX_PEERS)
756 }
757
758 Validator&
760 {
761 assert(v < validators_.size());
762 return validators_[v];
763 }
764
767 {
768 return overlay_;
769 }
770
771 void
772 enableLink(std::uint16_t validatorId, Peer::id_t peer, bool enable)
773 {
774 auto it =
775 std::find_if(validators_.begin(), validators_.end(), [&](auto& v) {
776 return v.id() == validatorId;
777 });
778 assert(it != validators_.end());
779 if (enable)
780 it->linkUp(peer);
781 else
782 it->linkDown(peer);
783 }
784
785 void
787 {
788 // Send unsquelch to the Peer on all links. This way when
789 // the Peer "reconnects" it starts sending messages on the link.
790 // We expect that if a Peer disconnects and then reconnects, it's
791 // unsquelched.
792 protocol::TMSquelch squelch;
793 squelch.set_squelch(false);
794 for (auto& v : validators_)
795 {
796 PublicKey key = v;
797 squelch.clear_validatorpubkey();
798 squelch.set_validatorpubkey(key.data(), key.size());
799 v.for_links({peer}, [&](Link& l, MessageSPtr) {
800 std::dynamic_pointer_cast<PeerSim>(l.getPeer())->send(squelch);
801 });
802 }
803 }
804
805 void
807 std::uint32_t min,
808 std::uint32_t max,
810 {
811 auto size = max - min;
813 std::iota(s.begin(), s.end(), min);
815 std::mt19937 g(d());
816 std::shuffle(s.begin(), s.end(), g);
817 for (auto v : s)
818 f(v);
819 }
820
821 void
823 LinkIterCB link,
824 std::uint16_t nValidators = MAX_VALIDATORS,
825 std::uint32_t nMessages = MAX_MESSAGES,
826 bool purge = true,
827 bool resetClock = true)
828 {
829 if (resetClock)
831
832 if (purge)
833 {
834 purgePeers();
836 }
837
838 for (int m = 0; m < nMessages; ++m)
839 {
841 for_rand(0, nValidators, [&](std::uint32_t v) {
842 validators_[v].for_links(link);
843 });
844 }
845 }
846
848 bool
850 {
851 for (auto& v : validators_)
852 {
853 if (overlay_.isSelected(v, id))
854 return true;
855 }
856 return false;
857 }
858
863 bool
865 {
866 for (auto& v : validators_)
867 {
868 if (!overlay_.isSelected(v, peer))
869 continue;
870 auto peers = overlay_.getPeers(v);
871 for (auto& [_, v] : peers)
872 {
873 (void)_;
874 if (std::get<reduce_relay::PeerState>(v) ==
876 return false;
877 }
878 }
879 return true;
880 }
881
882private:
885};
886
888{
891
892protected:
893 void
895 {
897 std::cout << msg << " " << "num peers "
898 << (int)network_.overlay().getNumPeers() << std::endl;
899 for (auto& [k, v] : peers)
900 std::cout << k << ":" << (int)std::get<reduce_relay::PeerState>(v)
901 << " ";
903 }
904
908 PublicKey const& validator,
909 PeerWPtr const& peerPtr,
911 {
912 protocol::TMSquelch squelch;
913 bool res = duration ? true : false;
914 squelch.set_squelch(res);
915 squelch.set_validatorpubkey(validator.data(), validator.size());
916 if (res)
917 squelch.set_squelchduration(*duration);
918 auto sp = peerPtr.lock();
919 assert(sp);
920 std::dynamic_pointer_cast<PeerSim>(sp)->send(squelch);
921 return sp->id();
922 }
923
924 enum State { On, Off, WaitReset };
926 // Link down or Peer disconnect event
927 // TBD - add new peer event
928 // TBD - add overlapping type of events at any
929 // time in any quantity
930 struct Event
931 {
935 bool isSelected_ = false;
940 bool handled_ = false;
941 };
942
946 void
948 {
950 {LinkDown, {}}, {PeerDisconnected, {}}};
952
953 network_.reset();
954 network_.propagate([&](Link& link, MessageSPtr m) {
955 auto& validator = link.validator();
956 auto now = ManualClock::now();
957
958 bool squelched = false;
960
961 link.send(
962 m,
963 [&](PublicKey const& key,
964 PeerWPtr const& peerPtr,
966 assert(key == validator);
967 auto p = sendSquelch(key, peerPtr, duration);
968 squelched = true;
969 str << p << " ";
970 });
971
972 if (squelched)
973 {
974 auto selected = network_.overlay().getSelected(validator);
975 str << " selected: ";
976 for (auto s : selected)
977 str << s << " ";
978 if (log)
980 << (double)reduce_relay::epoch<milliseconds>(now)
981 .count() /
982 1000.
983 << " random, squelched, validator: " << validator.id()
984 << " peers: " << str.str() << std::endl;
985 auto countingState =
987 BEAST_EXPECT(
988 countingState == false &&
989 selected.size() == reduce_relay::MAX_SELECTED_PEERS);
990 }
991
992 // Trigger Link Down or Peer Disconnect event
993 // Only one Link Down at a time
994 if (events[EventType::LinkDown].state_ == State::Off)
995 {
996 auto update = [&](EventType event) {
997 events[event].cnt_++;
998 events[event].validator_ = validator.id();
999 events[event].key_ = validator;
1000 events[event].peer_ = link.peerId();
1001 events[event].state_ = State::On;
1002 events[event].time_ = now;
1003 if (event == EventType::LinkDown)
1004 {
1006 validator.id(), link.peerId(), false);
1007 events[event].isSelected_ =
1009 validator, link.peerId());
1010 }
1011 else
1012 events[event].isSelected_ =
1013 network_.isSelected(link.peerId());
1014 };
1015 auto r = rand_int(0, 1000);
1016 if (r == (int)EventType::LinkDown ||
1018 {
1019 update(static_cast<EventType>(r));
1020 }
1021 }
1022
1023 if (events[EventType::PeerDisconnected].state_ == State::On)
1024 {
1025 auto& event = events[EventType::PeerDisconnected];
1026 bool allCounting = network_.allCounting(event.peer_);
1028 event.peer_,
1029 [&](PublicKey const& v, PeerWPtr const& peerPtr) {
1030 if (event.isSelected_)
1031 sendSquelch(v, peerPtr, {});
1032 event.handled_ = true;
1033 });
1034 // Should only be unsquelched if the peer is in Selected state
1035 // If in Selected state it's possible unsquelching didn't
1036 // take place because there is no peers in Squelched state in
1037 // any of the slots where the peer is in Selected state
1038 // (allCounting is true)
1039 bool handled =
1040 (event.isSelected_ == false && !event.handled_) ||
1041 (event.isSelected_ == true &&
1042 (event.handled_ || allCounting));
1043 BEAST_EXPECT(handled);
1044 event.state_ = State::Off;
1045 event.isSelected_ = false;
1046 event.handledCnt_ += handled;
1047 event.handled_ = false;
1048 network_.onDisconnectPeer(event.peer_);
1049 }
1050
1051 auto& event = events[EventType::LinkDown];
1052 // Check every sec for idled peers. Idled peers are
1053 // created by Link Down event.
1054 if (now - lastCheck > milliseconds(1000))
1055 {
1056 lastCheck = now;
1057 // Check if Link Down event must be handled by
1058 // deleteIdlePeer(): 1) the peer is in Selected state;
1059 // 2) the peer has not received any messages for IDLED time;
1060 // 3) there are peers in Squelched state in the slot.
1061 // 4) peer is in Slot's peers_ (if not then it is deleted
1062 // by Slots::deleteIdlePeers())
1063 bool mustHandle = false;
1064 if (event.state_ == State::On && BEAST_EXPECT(event.key_))
1065 {
1066 event.isSelected_ =
1067 network_.overlay().isSelected(*event.key_, event.peer_);
1068 auto peers = network_.overlay().getPeers(*event.key_);
1069 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1070 std::get<3>(peers[event.peer_]);
1071 mustHandle = event.isSelected_ &&
1075 0 &&
1076 peers.find(event.peer_) != peers.end();
1077 }
1079 [&](PublicKey const& v, PeerWPtr const& ptr) {
1080 event.handled_ = true;
1081 if (mustHandle && v == event.key_)
1082 {
1083 event.state_ = State::WaitReset;
1084 sendSquelch(validator, ptr, {});
1085 }
1086 });
1087 bool handled =
1088 (event.handled_ && event.state_ == State::WaitReset) ||
1089 (!event.handled_ && !mustHandle);
1090 BEAST_EXPECT(handled);
1091 }
1092 if (event.state_ == State::WaitReset ||
1093 (event.state_ == State::On &&
1094 (now - event.time_ > (reduce_relay::IDLED + seconds(2)))))
1095 {
1096 bool handled =
1097 event.state_ == State::WaitReset || !event.handled_;
1098 BEAST_EXPECT(handled);
1099 event.state_ = State::Off;
1100 event.isSelected_ = false;
1101 event.handledCnt_ += handled;
1102 event.handled_ = false;
1103 network_.enableLink(event.validator_, event.peer_, true);
1104 }
1105 });
1106
1107 auto& down = events[EventType::LinkDown];
1108 auto& disconnected = events[EventType::PeerDisconnected];
1109 // It's possible the last Down Link event is not handled
1110 BEAST_EXPECT(down.handledCnt_ >= down.cnt_ - 1);
1111 // All Peer Disconnect events must be handled
1112 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1113 if (log)
1114 std::cout << "link down count: " << down.cnt_ << "/"
1115 << down.handledCnt_
1116 << " peer disconnect count: " << disconnected.cnt_ << "/"
1117 << disconnected.handledCnt_;
1118 }
1119
1120 bool
1121 checkCounting(PublicKey const& validator, bool isCountingState)
1122 {
1123 auto countingState = network_.overlay().isCountingState(validator);
1124 BEAST_EXPECT(countingState == isCountingState);
1125 return countingState == isCountingState;
1126 }
1127
1128 void
1129 doTest(const std::string& msg, bool log, std::function<void(bool)> f)
1130 {
1131 testcase(msg);
1132 f(log);
1133 }
1134
1140 void
1142 {
1143 doTest("Initial Round", log, [this](bool log) {
1144 BEAST_EXPECT(propagateAndSquelch(log));
1145 });
1146 }
1147
1151 void
1153 {
1154 doTest("Peer Unsquelched Too Soon", log, [this](bool log) {
1155 BEAST_EXPECT(propagateNoSquelch(log, 1, false, false, false));
1156 });
1157 }
1158
1162 void
1164 {
1165 ManualClock::advance(seconds(601));
1166 doTest("Peer Unsquelched", log, [this](bool log) {
1167 BEAST_EXPECT(propagateNoSquelch(log, 2, true, true, false));
1168 });
1169 }
1170
1172 bool
1173 propagateAndSquelch(bool log, bool purge = true, bool resetClock = true)
1174 {
1175 int n = 0;
1176 network_.propagate(
1177 [&](Link& link, MessageSPtr message) {
1178 std::uint16_t squelched = 0;
1179 link.send(
1180 message,
1181 [&](PublicKey const& key,
1182 PeerWPtr const& peerPtr,
1184 squelched++;
1185 sendSquelch(key, peerPtr, duration);
1186 });
1187 if (squelched)
1188 {
1189 BEAST_EXPECT(
1190 squelched ==
1192 n++;
1193 }
1194 },
1195 1,
1197 purge,
1198 resetClock);
1199 auto selected = network_.overlay().getSelected(network_.validator(0));
1200 BEAST_EXPECT(selected.size() == reduce_relay::MAX_SELECTED_PEERS);
1201 BEAST_EXPECT(n == 1); // only one selection round
1202 auto res = checkCounting(network_.validator(0), false);
1203 BEAST_EXPECT(res);
1204 return n == 1 && res;
1205 }
1206
1208 bool
1210 bool log,
1211 std::uint16_t nMessages,
1212 bool countingState,
1213 bool purge = true,
1214 bool resetClock = true)
1215 {
1216 bool squelched = false;
1217 network_.propagate(
1218 [&](Link& link, MessageSPtr message) {
1219 link.send(
1220 message,
1221 [&](PublicKey const& key,
1222 PeerWPtr const& peerPtr,
1224 squelched = true;
1225 BEAST_EXPECT(false);
1226 });
1227 },
1228 1,
1229 nMessages,
1230 purge,
1231 resetClock);
1232 auto res = checkCounting(network_.validator(0), countingState);
1233 return !squelched && res;
1234 }
1235
1239 void
1240 testNewPeer(bool log)
1241 {
1242 doTest("New Peer", log, [this](bool log) {
1243 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1244 network_.addPeer();
1245 BEAST_EXPECT(propagateNoSquelch(log, 1, true, false, false));
1246 });
1247 }
1248
1251 void
1253 {
1254 doTest("Selected Peer Disconnects", log, [this](bool log) {
1255 ManualClock::advance(seconds(601));
1256 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1257 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1258 std::uint16_t unsquelched = 0;
1259 network_.overlay().deletePeer(
1260 id, [&](PublicKey const& key, PeerWPtr const& peer) {
1261 unsquelched++;
1262 });
1263 BEAST_EXPECT(
1265 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1266 });
1267 }
1268
1271 void
1273 {
1274 doTest("Selected Peer Stops Relaying", log, [this](bool log) {
1275 ManualClock::advance(seconds(601));
1276 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1277 ManualClock::advance(reduce_relay::IDLED + seconds(1));
1278 std::uint16_t unsquelched = 0;
1279 network_.overlay().deleteIdlePeers(
1280 [&](PublicKey const& key, PeerWPtr const& peer) {
1281 unsquelched++;
1282 });
1283 auto peers = network_.overlay().getPeers(network_.validator(0));
1284 BEAST_EXPECT(
1286 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1287 });
1288 }
1289
1292 void
1294 {
1295 doTest("Squelched Peer Disconnects", log, [this](bool log) {
1296 ManualClock::advance(seconds(601));
1297 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1298 auto peers = network_.overlay().getPeers(network_.validator(0));
1299 auto it = std::find_if(peers.begin(), peers.end(), [&](auto it) {
1300 return std::get<reduce_relay::PeerState>(it.second) ==
1301 reduce_relay::PeerState::Squelched;
1302 });
1303 assert(it != peers.end());
1304 std::uint16_t unsquelched = 0;
1305 network_.overlay().deletePeer(
1306 it->first, [&](PublicKey const& key, PeerWPtr const& peer) {
1307 unsquelched++;
1308 });
1309 BEAST_EXPECT(unsquelched == 0);
1310 BEAST_EXPECT(checkCounting(network_.validator(0), false));
1311 });
1312 }
1313
1314 void
1315 testConfig(bool log)
1316 {
1317 doTest("Config Test", log, [&](bool log) {
1318 Config c;
1319
1320 std::string toLoad(R"rippleConfig(
1321[reduce_relay]
1322vp_enable=1
1323vp_squelch=1
1324)rippleConfig");
1325
1326 c.loadFromString(toLoad);
1327 BEAST_EXPECT(c.VP_REDUCE_RELAY_ENABLE == true);
1328 BEAST_EXPECT(c.VP_REDUCE_RELAY_SQUELCH == true);
1329
1330 Config c1;
1331
1332 toLoad = (R"rippleConfig(
1333[reduce_relay]
1334vp_enable=0
1335vp_squelch=0
1336)rippleConfig");
1337
1338 c1.loadFromString(toLoad);
1339 BEAST_EXPECT(c1.VP_REDUCE_RELAY_ENABLE == false);
1340 BEAST_EXPECT(c1.VP_REDUCE_RELAY_SQUELCH == false);
1341
1342 Config c2;
1343
1344 toLoad = R"rippleConfig(
1345[reduce_relay]
1346vp_enabled=1
1347vp_squelched=1
1348)rippleConfig";
1349
1350 c2.loadFromString(toLoad);
1351 BEAST_EXPECT(c2.VP_REDUCE_RELAY_ENABLE == false);
1352 BEAST_EXPECT(c2.VP_REDUCE_RELAY_SQUELCH == false);
1353 });
1354 }
1355
1356 void
1358 {
1359 doTest("Duplicate Message", log, [&](bool log) {
1360 network_.reset();
1361 // update message count for the same peer/validator
1362 std::int16_t nMessages = 5;
1363 for (int i = 0; i < nMessages; i++)
1364 {
1365 uint256 key(i);
1366 network_.overlay().updateSlotAndSquelch(
1367 key,
1368 network_.validator(0),
1369 0,
1370 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1371 }
1372 auto peers = network_.overlay().getPeers(network_.validator(0));
1373 // first message changes Slot state to Counting and is not counted,
1374 // hence '-1'.
1375 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1376 // add duplicate
1377 uint256 key(nMessages - 1);
1378 network_.overlay().updateSlotAndSquelch(
1379 key,
1380 network_.validator(0),
1381 0,
1382 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1383 // confirm the same number of messages
1384 peers = network_.overlay().getPeers(network_.validator(0));
1385 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1386 // advance the clock
1387 ManualClock::advance(reduce_relay::IDLED + seconds(1));
1388 network_.overlay().updateSlotAndSquelch(
1389 key,
1390 network_.validator(0),
1391 0,
1392 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1393 peers = network_.overlay().getPeers(network_.validator(0));
1394 // confirm message number increased
1395 BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
1396 });
1397 }
1398
1400 {
1401 Handler() : maxDuration_(0)
1402 {
1403 }
1404 void
1406 const override
1407 {
1408 if (duration > maxDuration_)
1409 maxDuration_ = duration;
1410 }
1411 void
1412 unsquelch(PublicKey const&, Peer::id_t) const override
1413 {
1414 }
1415 mutable int maxDuration_;
1416 };
1417
1418 void
1420 {
1421 doTest("Random Squelch", l, [&](bool l) {
1423 Handler handler;
1424
1425 auto run = [&](int npeers) {
1426 handler.maxDuration_ = 0;
1428 env_.app().logs(), handler);
1429 // 1st message from a new peer switches the slot
1430 // to counting state and resets the counts of all peers +
1431 // MAX_MESSAGE_THRESHOLD + 1 messages to reach the threshold
1432 // and switch the slot's state to peer selection.
1433 for (int m = 1; m <= reduce_relay::MAX_MESSAGE_THRESHOLD + 2;
1434 m++)
1435 {
1436 for (int peer = 0; peer < npeers; peer++)
1437 {
1438 // make unique message hash to make the
1439 // slot's internal hash router accept the message
1440 std::uint64_t mid = m * 1000 + peer;
1441 uint256 const message{mid};
1443 message,
1444 validator,
1445 peer,
1446 protocol::MessageType::mtVALIDATION);
1447 }
1448 }
1449 // make Slot's internal hash router expire all messages
1450 ManualClock::advance(hours(1));
1451 };
1452
1453 using namespace reduce_relay;
1454 // expect max duration less than MAX_UNSQUELCH_EXPIRE_DEFAULT with
1455 // less than or equal to 60 peers
1456 run(20);
1457 BEAST_EXPECT(
1458 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1459 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1460 run(60);
1461 BEAST_EXPECT(
1462 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1463 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1464 // expect max duration greater than MIN_UNSQUELCH_EXPIRE and less
1465 // than MAX_UNSQUELCH_EXPIRE_PEERS with peers greater than 60
1466 // and less than 360
1467 run(350);
1468 // can't make this condition stronger. squelch
1469 // duration is probabilistic and max condition may still fail.
1470 // log when the value is low
1471 BEAST_EXPECT(
1472 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1473 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1474 using namespace beast::unit_test::detail;
1475 if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1476 log << make_reason(
1477 "warning: squelch duration is low",
1478 __FILE__,
1479 __LINE__)
1480 << std::endl
1481 << std::flush;
1482 // more than 400 is still less than MAX_UNSQUELCH_EXPIRE_PEERS
1483 run(400);
1484 BEAST_EXPECT(
1485 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1486 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1487 if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1488 log << make_reason(
1489 "warning: squelch duration is low",
1490 __FILE__,
1491 __LINE__)
1492 << std::endl
1493 << std::flush;
1494 });
1495 }
1496
1497 void
1499 {
1500 doTest("Handshake", log, [&](bool log) {
1501 auto setEnv = [&](bool enable) {
1502 Config c;
1504 str << "[reduce_relay]\n"
1505 << "vp_enable=" << enable << "\n"
1506 << "vp_squelch=" << enable << "\n"
1507 << "[compression]\n"
1508 << "1\n";
1509 c.loadFromString(str.str());
1510 env_.app().config().VP_REDUCE_RELAY_ENABLE =
1512 env_.app().config().VP_REDUCE_RELAY_SQUELCH =
1514 env_.app().config().COMPRESSION = c.COMPRESSION;
1515 };
1516 auto handshake = [&](int outboundEnable, int inboundEnable) {
1517 beast::IP::Address addr =
1518 boost::asio::ip::address::from_string("172.1.1.100");
1519
1520 setEnv(outboundEnable);
1521 auto request = ripple::makeRequest(
1522 true,
1523 env_.app().config().COMPRESSION,
1524 false,
1525 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1526 env_.app().config().VP_REDUCE_RELAY_ENABLE);
1527 http_request_type http_request;
1528 http_request.version(request.version());
1529 http_request.base() = request.base();
1530 // feature enabled on the peer's connection only if both sides
1531 // are enabled
1532 auto const peerEnabled = inboundEnable && outboundEnable;
1533 // inbound is enabled if the request's header has the feature
1534 // enabled and the peer's configuration is enabled
1535 auto const inboundEnabled = peerFeatureEnabled(
1536 http_request, FEATURE_VPRR, inboundEnable);
1537 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1538
1539 setEnv(inboundEnable);
1540 auto http_resp = ripple::makeResponse(
1541 true,
1542 http_request,
1543 addr,
1544 addr,
1545 uint256{1},
1546 1,
1547 {1, 0},
1548 env_.app());
1549 // outbound is enabled if the response's header has the feature
1550 // enabled and the peer's configuration is enabled
1551 auto const outboundEnabled =
1552 peerFeatureEnabled(http_resp, FEATURE_VPRR, outboundEnable);
1553 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1554 };
1555 handshake(1, 1);
1556 handshake(1, 0);
1557 handshake(0, 1);
1558 handshake(0, 0);
1559 });
1560 }
1561
1564
1565public:
1566 reduce_relay_test() : env_(*this), network_(env_.app())
1567 {
1568 }
1569
1570 void
1571 run() override
1572 {
1573 bool log = false;
1574 testConfig(log);
1575 testInitialRound(log);
1576 testPeerUnsquelchedTooSoon(log);
1577 testPeerUnsquelched(log);
1578 testNewPeer(log);
1579 testSquelchedPeerDisconnects(log);
1580 testSelectedPeerDisconnects(log);
1581 testSelectedPeerStopsRelaying(log);
1582 testInternalHashRouter(log);
1583 testRandomSquelch(log);
1584 testHandshake(log);
1585 }
1586};
1587
1589{
1590 void
1591 testRandom(bool log)
1592 {
1593 doTest("Random Test", log, [&](bool log) { random(log); });
1594 }
1595
1596 void
1597 run() override
1598 {
1599 bool log = false;
1600 testRandom(log);
1601 }
1602};
1603
1604BEAST_DEFINE_TESTSUITE(reduce_relay, ripple_data, ripple);
1605BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, ripple_data, ripple);
1606
1607} // namespace test
1608
1609} // 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
std::set< std::optional< uint64_t > > releaseRequestCookies(uint256 const &requestHash) 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)