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
20#include <test/jtx.h>
21#include <test/jtx/Env.h>
22
23#include <xrpld/overlay/Message.h>
24#include <xrpld/overlay/Peer.h>
25#include <xrpld/overlay/Slot.h>
26#include <xrpld/overlay/Squelch.h>
27#include <xrpld/overlay/detail/Handshake.h>
28
29#include <xrpl/basics/random.h>
30#include <xrpl/beast/unit_test.h>
31#include <xrpl/protocol/SecretKey.h>
32#include <xrpl/protocol/messages.h>
33
34#include <boost/thread.hpp>
35
36#include <chrono>
37#include <iostream>
38#include <numeric>
39#include <optional>
40
41namespace ripple {
42
43namespace test {
44
45using namespace std::chrono;
46
47class Link;
48
53using SquelchCB =
54 std::function<void(PublicKey const&, PeerWPtr const&, std::uint32_t)>;
55using UnsquelchCB = std::function<void(PublicKey const&, PeerWPtr const&)>;
57
58static constexpr std::uint32_t MAX_PEERS = 10;
59static constexpr std::uint32_t MAX_VALIDATORS = 10;
60static constexpr std::uint32_t MAX_MESSAGES = 200000;
61
65class PeerPartial : public Peer
66{
67public:
72
74 virtual ~PeerPartial()
75 {
76 }
77 virtual void
79 virtual void
80 onMessage(protocol::TMSquelch const& squelch) = 0;
81 void
82 send(protocol::TMSquelch const& squelch)
83 {
85 }
86
87 // dummy implementation
88 void
89 send(std::shared_ptr<Message> const& m) override
90 {
91 }
93 getRemoteAddress() const override
94 {
95 return {};
96 }
97 void
98 charge(Resource::Charge const& fee, std::string const& context = {})
99 override
100 {
101 }
102 bool
103 cluster() const override
104 {
105 return false;
106 }
107 bool
108 isHighLatency() const override
109 {
110 return false;
111 }
112 int
113 getScore(bool) const override
114 {
115 return 0;
116 }
117 PublicKey const&
118 getNodePublic() const override
119 {
120 return nodePublicKey_;
121 }
123 json() override
124 {
125 return {};
126 }
127 bool
129 {
130 return false;
131 }
133 publisherListSequence(PublicKey const&) const override
134 {
135 return {};
136 }
137 void
139 {
140 }
141 uint256 const&
142 getClosedLedgerHash() const override
143 {
144 static uint256 hash{};
145 return hash;
146 }
147 bool
148 hasLedger(uint256 const& hash, std::uint32_t seq) const override
149 {
150 return false;
151 }
152 void
153 ledgerRange(std::uint32_t& minSeq, std::uint32_t& maxSeq) const override
154 {
155 }
156 bool
157 hasTxSet(uint256 const& hash) const override
158 {
159 return false;
160 }
161 void
162 cycleStatus() override
163 {
164 }
165 bool
167 {
168 return false;
169 }
170 bool
171 compressionEnabled() const override
172 {
173 return false;
174 }
175 bool
176 txReduceRelayEnabled() const override
177 {
178 return false;
179 }
180 void
181 sendTxQueue() override
182 {
183 }
184 void
185 addTxQueue(uint256 const&) override
186 {
187 }
188 void
189 removeTxQueue(uint256 const&) override
190 {
191 }
192};
193
196{
197public:
198 typedef uint64_t rep;
202 inline static bool const is_steady = false;
203
204 static void
205 advance(duration d) noexcept
206 {
207 now_ += d;
208 }
209
210 static void
212 {
213 now_ += randDuration(min, max);
214 }
215
216 static void
217 reset() noexcept
218 {
219 now_ = time_point(seconds(0));
220 }
221
222 static time_point
223 now() noexcept
224 {
225 return now_;
226 }
227
228 static duration
230 {
231 return duration(milliseconds(rand_int(min.count(), max.count())));
232 }
233
234 explicit ManualClock() = default;
235
236private:
237 inline static time_point now_ = time_point(seconds(0));
238};
239
242{
243public:
244 Overlay() = default;
245 virtual ~Overlay() = default;
246
247 virtual void
249 uint256 const& key,
250 PublicKey const& validator,
251 Peer::id_t id,
252 SquelchCB f,
253 protocol::MessageType type = protocol::mtVALIDATION) = 0;
254
255 virtual void deleteIdlePeers(UnsquelchCB) = 0;
256
258};
259
260class Validator;
261
265class Link
266{
268
269public:
272 PeerSPtr peer,
273 Latency const& latency = {milliseconds(5), milliseconds(15)})
274 : validator_(validator), peer_(peer), latency_(latency), up_(true)
275 {
276 auto sp = peer_.lock();
277 assert(sp);
278 }
279 ~Link() = default;
280 void
282 {
283 if (!up_)
284 return;
285 auto sp = peer_.lock();
286 assert(sp);
288 peer->onMessage(m, f);
289 }
290 Validator&
292 {
293 return validator_;
294 }
295 void
296 up(bool linkUp)
297 {
298 up_ = linkUp;
299 }
302 {
303 auto p = peer_.lock();
304 assert(p);
305 return p->id();
306 }
309 {
310 auto p = peer_.lock();
311 assert(p);
312 return p;
313 }
314
315private:
319 bool up_;
320};
321
324{
326
327public:
329 {
330 protocol::TMValidation v;
331 v.set_validation("validation");
332 message_ = std::make_shared<Message>(v, protocol::mtVALIDATION, pkey_);
333 id_ = sid_++;
334 }
335 Validator(Validator const&) = default;
336 Validator(Validator&&) = default;
337 Validator&
338 operator=(Validator const&) = default;
339 Validator&
340 operator=(Validator&&) = default;
342 {
343 clear();
344 }
345
346 void
348 {
349 links_.clear();
350 }
351
352 static void
354 {
355 sid_ = 0;
356 }
357
358 PublicKey const&
360 {
361 return pkey_;
362 }
363
364 operator PublicKey() const
365 {
366 return pkey_;
367 }
368
369 void
371 {
373 std::make_pair(peer->id(), std::make_shared<Link>(*this, peer)));
374 }
375
376 void
378 {
379 links_.erase(id);
380 }
381
382 void
384 {
385 for (auto id : peers)
386 {
387 assert(links_.find(id) != links_.end());
388 f(*links_[id], message_);
389 }
390 }
391
392 void
393 for_links(LinkIterCB f, bool simulateSlow = false)
394 {
397 links_.begin(), links_.end(), std::back_inserter(v), [](auto& kv) {
398 return kv.second;
399 });
401 std::mt19937 g(d());
402 std::shuffle(v.begin(), v.end(), g);
403
404 for (auto& link : v)
405 {
406 f(*link, message_);
407 }
408 }
409
411 void
413 {
414 for_links(peers, [&](Link& link, MessageSPtr m) { link.send(m, f); });
415 }
416
418 void
420 {
421 for_links([&](Link& link, MessageSPtr m) { link.send(m, f); });
422 }
423
426 {
427 return message_;
428 }
429
432 {
433 return id_;
434 }
435
436 void
438 {
439 auto it = links_.find(id);
440 assert(it != links_.end());
441 it->second->up(true);
442 }
443
444 void
446 {
447 auto it = links_.find(id);
448 assert(it != links_.end());
449 it->second->up(false);
450 }
451
452private:
456 inline static std::uint16_t sid_ = 0;
458};
459
460class PeerSim : public PeerPartial, public std::enable_shared_from_this<PeerSim>
461{
462public:
464 PeerSim(Overlay& overlay, beast::Journal journal)
465 : overlay_(overlay), squelch_(journal)
466 {
467 id_ = sid_++;
468 }
469
470 ~PeerSim() = default;
471
472 id_t
473 id() const override
474 {
475 return id_;
476 }
477
478 static void
480 {
481 sid_ = 0;
482 }
483
485 void
486 onMessage(MessageSPtr const& m, SquelchCB f) override
487 {
488 auto validator = m->getValidatorKey();
489 assert(validator);
490 if (!squelch_.expireSquelch(*validator))
491 return;
492
494 }
495
497 virtual void
498 onMessage(protocol::TMSquelch const& squelch) override
499 {
500 auto validator = squelch.validatorpubkey();
501 PublicKey key(Slice(validator.data(), validator.size()));
502 if (squelch.squelch())
503 squelch_.addSquelch(
504 key, std::chrono::seconds{squelch.squelchduration()});
505 else
506 squelch_.removeSquelch(key);
507 }
508
509private:
510 inline static id_t sid_ = 0;
514};
515
517{
519
520public:
524 : slots_(app.logs(), *this, app.config()), logs_(app.logs())
525 {
526 }
527
528 ~OverlaySim() = default;
529
530 void
532 {
533 peers_.clear();
535 slots_.deleteIdlePeers();
536 }
537
540 {
541 auto res = slots_.inState(validator, state);
542 return res ? *res : 0;
543 }
544
545 void
547 uint256 const& key,
548 PublicKey const& validator,
549 Peer::id_t id,
550 SquelchCB f,
551 protocol::MessageType type = protocol::mtVALIDATION) override
552 {
553 squelch_ = f;
554 slots_.updateSlotAndSquelch(key, validator, id, type);
555 }
556
557 void
559 {
560 unsquelch_ = f;
561 slots_.deletePeer(id, true);
562 }
563
564 void
566 {
567 unsquelch_ = f;
568 slots_.deleteIdlePeers();
569 }
570
572 addPeer(bool useCache = true)
573 {
574 PeerSPtr peer{};
575 Peer::id_t id;
576 if (peersCache_.empty() || !useCache)
577 {
578 peer = std::make_shared<PeerSim>(*this, logs_.journal("Squelch"));
579 id = peer->id();
580 }
581 else
582 {
583 auto it = peersCache_.begin();
584 peer = it->second;
585 id = it->first;
586 peersCache_.erase(it);
587 }
588 peers_.emplace(std::make_pair(id, peer));
589 return peer;
590 }
591
592 void
593 deletePeer(Peer::id_t id, bool useCache = true)
594 {
595 auto it = peers_.find(id);
596 assert(it != peers_.end());
597 deletePeer(id, [&](PublicKey const&, PeerWPtr) {});
598 if (useCache)
599 peersCache_.emplace(std::make_pair(id, it->second));
600 peers_.erase(it);
601 }
602
603 void
605 {
606 while (!peers_.empty())
607 deletePeer(peers_.begin()->first);
608 while (!peersCache_.empty())
609 addPeer();
610 }
611
614 {
615 if (peers_.empty())
616 return {};
617
618 std::uint8_t maxId = 0;
619
620 for (auto& [id, _] : peers_)
621 {
622 (void)_;
623 if (id > maxId)
624 maxId = id;
625 }
626
627 deletePeer(maxId, false);
628
629 return maxId;
630 }
631
632 bool
637
640 {
641 return slots_.getSelected(validator);
642 }
643
644 bool
646 {
647 auto selected = slots_.getSelected(validator);
648 return selected.find(peer) != selected.end();
649 }
650
651 id_t
653 {
654 auto selected = slots_.getSelected(validator);
655 assert(selected.size());
656 return *selected.begin();
657 }
658
660 id_t,
667 {
668 return slots_.getPeers(validator);
669 }
670
673 {
674 return peers_.size();
675 }
676
677private:
678 void
680 PublicKey const& validator,
681 Peer::id_t id,
682 std::uint32_t squelchDuration) const override
683 {
684 if (auto it = peers_.find(id); it != peers_.end())
685 squelch_(validator, it->second, squelchDuration);
686 }
687 void
688 unsquelch(PublicKey const& validator, Peer::id_t id) const override
689 {
690 if (auto it = peers_.find(id); it != peers_.end())
691 unsquelch_(validator, it->second);
692 }
699};
700
702{
703public:
705 {
706 init();
707 }
708
709 void
711 {
713 for (int p = 0; p < MAX_PEERS; p++)
714 {
715 auto peer = overlay_.addPeer();
716 for (auto& v : validators_)
717 v.addPeer(peer);
718 }
719 }
720
721 ~Network() = default;
722
723 void
725 {
726 validators_.clear();
727 overlay_.clear();
730 init();
731 }
732
735 {
736 auto peer = overlay_.addPeer();
737 for (auto& v : validators_)
738 v.addPeer(peer);
739 return peer->id();
740 }
741
742 void
744 {
745 auto id = overlay_.deleteLastPeer();
746
747 if (!id)
748 return;
749
750 for (auto& validator : validators_)
752 }
753
754 void
756 {
757 while (overlay_.getNumPeers() > MAX_PEERS)
759 }
760
761 Validator&
763 {
764 assert(v < validators_.size());
765 return validators_[v];
766 }
767
770 {
771 return overlay_;
772 }
773
774 void
775 enableLink(std::uint16_t validatorId, Peer::id_t peer, bool enable)
776 {
777 auto it =
778 std::find_if(validators_.begin(), validators_.end(), [&](auto& v) {
779 return v.id() == validatorId;
780 });
781 assert(it != validators_.end());
782 if (enable)
783 it->linkUp(peer);
784 else
785 it->linkDown(peer);
786 }
787
788 void
790 {
791 // Send unsquelch to the Peer on all links. This way when
792 // the Peer "reconnects" it starts sending messages on the link.
793 // We expect that if a Peer disconnects and then reconnects, it's
794 // unsquelched.
795 protocol::TMSquelch squelch;
796 squelch.set_squelch(false);
797 for (auto& v : validators_)
798 {
799 PublicKey key = v;
800 squelch.clear_validatorpubkey();
801 squelch.set_validatorpubkey(key.data(), key.size());
802 v.for_links({peer}, [&](Link& l, MessageSPtr) {
804 });
805 }
806 }
807
808 void
810 std::uint32_t min,
811 std::uint32_t max,
813 {
814 auto size = max - min;
816 std::iota(s.begin(), s.end(), min);
818 std::mt19937 g(d());
819 std::shuffle(s.begin(), s.end(), g);
820 for (auto v : s)
821 f(v);
822 }
823
824 void
826 LinkIterCB link,
827 std::uint16_t nValidators = MAX_VALIDATORS,
828 std::uint32_t nMessages = MAX_MESSAGES,
829 bool purge = true,
830 bool resetClock = true)
831 {
832 if (resetClock)
834
835 if (purge)
836 {
837 purgePeers();
839 }
840
841 for (int m = 0; m < nMessages; ++m)
842 {
844 for_rand(0, nValidators, [&](std::uint32_t v) {
845 validators_[v].for_links(link);
846 });
847 }
848 }
849
851 bool
853 {
854 for (auto& v : validators_)
855 {
856 if (overlay_.isSelected(v, id))
857 return true;
858 }
859 return false;
860 }
861
866 bool
868 {
869 for (auto& v : validators_)
870 {
871 if (!overlay_.isSelected(v, peer))
872 continue;
873 auto peers = overlay_.getPeers(v);
874 for (auto& [_, v] : peers)
875 {
876 (void)_;
879 return false;
880 }
881 }
882 return true;
883 }
884
885private:
888};
889
891{
894
895protected:
896 void
898 {
900 std::cout << msg << " "
901 << "num peers " << (int)network_.overlay().getNumPeers()
902 << std::endl;
903 for (auto& [k, v] : peers)
904 std::cout << k << ":" << (int)std::get<reduce_relay::PeerState>(v)
905 << " ";
907 }
908
912 PublicKey const& validator,
913 PeerWPtr const& peerPtr,
915 {
916 protocol::TMSquelch squelch;
917 bool res = duration ? true : false;
918 squelch.set_squelch(res);
919 squelch.set_validatorpubkey(validator.data(), validator.size());
920 if (res)
921 squelch.set_squelchduration(*duration);
922 auto sp = peerPtr.lock();
923 assert(sp);
925 return sp->id();
926 }
927
928 enum State { On, Off, WaitReset };
930 // Link down or Peer disconnect event
931 // TBD - add new peer event
932 // TBD - add overlapping type of events at any
933 // time in any quantity
946
950 void
952 {
954 {LinkDown, {}}, {PeerDisconnected, {}}};
956
957 network_.reset();
958 network_.propagate([&](Link& link, MessageSPtr m) {
959 auto& validator = link.validator();
960 auto now = ManualClock::now();
961
962 bool squelched = false;
964
965 link.send(
966 m,
967 [&](PublicKey const& key,
968 PeerWPtr const& peerPtr,
970 assert(key == validator);
971 auto p = sendSquelch(key, peerPtr, duration);
972 squelched = true;
973 str << p << " ";
974 });
975
976 if (squelched)
977 {
978 auto selected = network_.overlay().getSelected(validator);
979 str << " selected: ";
980 for (auto s : selected)
981 str << s << " ";
982 if (log)
984 << (double)reduce_relay::epoch<milliseconds>(now)
985 .count() /
986 1000.
987 << " random, squelched, validator: " << validator.id()
988 << " peers: " << str.str() << std::endl;
989 auto countingState =
991 BEAST_EXPECT(
992 countingState == false &&
993 selected.size() ==
994 env_.app()
995 .config()
997 }
998
999 // Trigger Link Down or Peer Disconnect event
1000 // Only one Link Down at a time
1001 if (events[EventType::LinkDown].state_ == State::Off)
1002 {
1003 auto update = [&](EventType event) {
1004 events[event].cnt_++;
1005 events[event].validator_ = validator.id();
1006 events[event].key_ = validator;
1007 events[event].peer_ = link.peerId();
1008 events[event].state_ = State::On;
1009 events[event].time_ = now;
1010 if (event == EventType::LinkDown)
1011 {
1013 validator.id(), link.peerId(), false);
1014 events[event].isSelected_ =
1016 validator, link.peerId());
1017 }
1018 else
1019 events[event].isSelected_ =
1020 network_.isSelected(link.peerId());
1021 };
1022 auto r = rand_int(0, 1000);
1023 if (r == (int)EventType::LinkDown ||
1025 {
1026 update(static_cast<EventType>(r));
1027 }
1028 }
1029
1030 if (events[EventType::PeerDisconnected].state_ == State::On)
1031 {
1032 auto& event = events[EventType::PeerDisconnected];
1033 bool allCounting = network_.allCounting(event.peer_);
1035 event.peer_,
1036 [&](PublicKey const& v, PeerWPtr const& peerPtr) {
1037 if (event.isSelected_)
1038 sendSquelch(v, peerPtr, {});
1039 event.handled_ = true;
1040 });
1041 // Should only be unsquelched if the peer is in Selected state
1042 // If in Selected state it's possible unsquelching didn't
1043 // take place because there is no peers in Squelched state in
1044 // any of the slots where the peer is in Selected state
1045 // (allCounting is true)
1046 bool handled =
1047 (event.isSelected_ == false && !event.handled_) ||
1048 (event.isSelected_ == true &&
1049 (event.handled_ || allCounting));
1050 BEAST_EXPECT(handled);
1051 event.state_ = State::Off;
1052 event.isSelected_ = false;
1053 event.handledCnt_ += handled;
1054 event.handled_ = false;
1055 network_.onDisconnectPeer(event.peer_);
1056 }
1057
1058 auto& event = events[EventType::LinkDown];
1059 // Check every sec for idled peers. Idled peers are
1060 // created by Link Down event.
1061 if (now - lastCheck > milliseconds(1000))
1062 {
1063 lastCheck = now;
1064 // Check if Link Down event must be handled by
1065 // deleteIdlePeer(): 1) the peer is in Selected state;
1066 // 2) the peer has not received any messages for IDLED time;
1067 // 3) there are peers in Squelched state in the slot.
1068 // 4) peer is in Slot's peers_ (if not then it is deleted
1069 // by Slots::deleteIdlePeers())
1070 bool mustHandle = false;
1071 if (event.state_ == State::On && BEAST_EXPECT(event.key_))
1072 {
1073 event.isSelected_ =
1074 network_.overlay().isSelected(*event.key_, event.peer_);
1075 auto peers = network_.overlay().getPeers(*event.key_);
1076 auto d = reduce_relay::epoch<milliseconds>(now).count() -
1077 std::get<3>(peers[event.peer_]);
1078 mustHandle = event.isSelected_ &&
1082 0 &&
1083 peers.find(event.peer_) != peers.end();
1084 }
1086 [&](PublicKey const& v, PeerWPtr const& ptr) {
1087 event.handled_ = true;
1088 if (mustHandle && v == event.key_)
1089 {
1090 event.state_ = State::WaitReset;
1091 sendSquelch(validator, ptr, {});
1092 }
1093 });
1094 bool handled =
1095 (event.handled_ && event.state_ == State::WaitReset) ||
1096 (!event.handled_ && !mustHandle);
1097 BEAST_EXPECT(handled);
1098 }
1099 if (event.state_ == State::WaitReset ||
1100 (event.state_ == State::On &&
1101 (now - event.time_ > (reduce_relay::IDLED + seconds(2)))))
1102 {
1103 bool handled =
1104 event.state_ == State::WaitReset || !event.handled_;
1105 BEAST_EXPECT(handled);
1106 event.state_ = State::Off;
1107 event.isSelected_ = false;
1108 event.handledCnt_ += handled;
1109 event.handled_ = false;
1110 network_.enableLink(event.validator_, event.peer_, true);
1111 }
1112 });
1113
1114 auto& down = events[EventType::LinkDown];
1115 auto& disconnected = events[EventType::PeerDisconnected];
1116 // It's possible the last Down Link event is not handled
1117 BEAST_EXPECT(down.handledCnt_ >= down.cnt_ - 1);
1118 // All Peer Disconnect events must be handled
1119 BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_);
1120 if (log)
1121 std::cout << "link down count: " << down.cnt_ << "/"
1122 << down.handledCnt_
1123 << " peer disconnect count: " << disconnected.cnt_ << "/"
1124 << disconnected.handledCnt_;
1125 }
1126
1127 bool
1128 checkCounting(PublicKey const& validator, bool isCountingState)
1129 {
1130 auto countingState = network_.overlay().isCountingState(validator);
1131 BEAST_EXPECT(countingState == isCountingState);
1132 return countingState == isCountingState;
1133 }
1134
1135 void
1136 doTest(std::string const& msg, bool log, std::function<void(bool)> f)
1137 {
1138 testcase(msg);
1139 f(log);
1140 }
1141
1147 void
1149 {
1150 doTest("Initial Round", log, [this](bool log) {
1151 BEAST_EXPECT(propagateAndSquelch(log));
1152 });
1153 }
1154
1158 void
1160 {
1161 doTest("Peer Unsquelched Too Soon", log, [this](bool log) {
1162 BEAST_EXPECT(propagateNoSquelch(log, 1, false, false, false));
1163 });
1164 }
1165
1169 void
1171 {
1172 ManualClock::advance(seconds(601));
1173 doTest("Peer Unsquelched", log, [this](bool log) {
1174 BEAST_EXPECT(propagateNoSquelch(log, 2, true, true, false));
1175 });
1176 }
1177
1179 bool
1180 propagateAndSquelch(bool log, bool purge = true, bool resetClock = true)
1181 {
1182 int n = 0;
1183 network_.propagate(
1184 [&](Link& link, MessageSPtr message) {
1185 std::uint16_t squelched = 0;
1186 link.send(
1187 message,
1188 [&](PublicKey const& key,
1189 PeerWPtr const& peerPtr,
1191 squelched++;
1192 sendSquelch(key, peerPtr, duration);
1193 });
1194 if (squelched)
1195 {
1196 BEAST_EXPECT(
1197 squelched ==
1198 MAX_PEERS -
1199 env_.app()
1200 .config()
1201 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1202 n++;
1203 }
1204 },
1205 1,
1207 purge,
1208 resetClock);
1209 auto selected = network_.overlay().getSelected(network_.validator(0));
1210 BEAST_EXPECT(
1211 selected.size() ==
1212 env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1213 BEAST_EXPECT(n == 1); // only one selection round
1214 auto res = checkCounting(network_.validator(0), false);
1215 BEAST_EXPECT(res);
1216 return n == 1 && res;
1217 }
1218
1220 bool
1222 bool log,
1223 std::uint16_t nMessages,
1224 bool countingState,
1225 bool purge = true,
1226 bool resetClock = true)
1227 {
1228 bool squelched = false;
1229 network_.propagate(
1230 [&](Link& link, MessageSPtr message) {
1231 link.send(
1232 message,
1233 [&](PublicKey const& key,
1234 PeerWPtr const& peerPtr,
1236 squelched = true;
1237 BEAST_EXPECT(false);
1238 });
1239 },
1240 1,
1241 nMessages,
1242 purge,
1243 resetClock);
1244 auto res = checkCounting(network_.validator(0), countingState);
1245 return !squelched && res;
1246 }
1247
1251 void
1252 testNewPeer(bool log)
1253 {
1254 doTest("New Peer", log, [this](bool log) {
1255 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1256 network_.addPeer();
1257 BEAST_EXPECT(propagateNoSquelch(log, 1, true, false, false));
1258 });
1259 }
1260
1263 void
1265 {
1266 doTest("Selected Peer Disconnects", log, [this](bool log) {
1267 ManualClock::advance(seconds(601));
1268 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1269 auto id = network_.overlay().getSelectedPeer(network_.validator(0));
1270 std::uint16_t unsquelched = 0;
1271 network_.overlay().deletePeer(
1272 id, [&](PublicKey const& key, PeerWPtr const& peer) {
1273 unsquelched++;
1274 });
1275 BEAST_EXPECT(
1276 unsquelched ==
1277 MAX_PEERS -
1278 env_.app()
1279 .config()
1280 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1281 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1282 });
1283 }
1284
1287 void
1289 {
1290 doTest("Selected Peer Stops Relaying", log, [this](bool log) {
1291 ManualClock::advance(seconds(601));
1292 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1293 ManualClock::advance(reduce_relay::IDLED + seconds(1));
1294 std::uint16_t unsquelched = 0;
1295 network_.overlay().deleteIdlePeers(
1296 [&](PublicKey const& key, PeerWPtr const& peer) {
1297 unsquelched++;
1298 });
1299 auto peers = network_.overlay().getPeers(network_.validator(0));
1300 BEAST_EXPECT(
1301 unsquelched ==
1302 MAX_PEERS -
1303 env_.app()
1304 .config()
1305 .VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS);
1306 BEAST_EXPECT(checkCounting(network_.validator(0), true));
1307 });
1308 }
1309
1312 void
1314 {
1315 doTest("Squelched Peer Disconnects", log, [this](bool log) {
1316 ManualClock::advance(seconds(601));
1317 BEAST_EXPECT(propagateAndSquelch(log, true, false));
1318 auto peers = network_.overlay().getPeers(network_.validator(0));
1319 auto it = std::find_if(peers.begin(), peers.end(), [&](auto it) {
1320 return std::get<reduce_relay::PeerState>(it.second) ==
1321 reduce_relay::PeerState::Squelched;
1322 });
1323 assert(it != peers.end());
1324 std::uint16_t unsquelched = 0;
1325 network_.overlay().deletePeer(
1326 it->first, [&](PublicKey const& key, PeerWPtr const& peer) {
1327 unsquelched++;
1328 });
1329 BEAST_EXPECT(unsquelched == 0);
1330 BEAST_EXPECT(checkCounting(network_.validator(0), false));
1331 });
1332 }
1333
1334 void
1335 testConfig(bool log)
1336 {
1337 doTest("Test Config - squelch enabled (legacy)", log, [&](bool log) {
1338 Config c;
1339
1340 std::string toLoad(R"rippleConfig(
1341[reduce_relay]
1342vp_enable=1
1343)rippleConfig");
1344
1345 c.loadFromString(toLoad);
1346 BEAST_EXPECT(c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE == true);
1347 });
1348
1349 doTest("Test Config - squelch disabled (legacy)", log, [&](bool log) {
1350 Config c;
1351
1352 std::string toLoad(R"rippleConfig(
1353[reduce_relay]
1354vp_enable=0
1355)rippleConfig");
1356
1357 c.loadFromString(toLoad);
1358 BEAST_EXPECT(c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE == false);
1359
1360 Config c1;
1361
1362 toLoad = R"rippleConfig(
1363[reduce_relay]
1364)rippleConfig";
1365
1366 c1.loadFromString(toLoad);
1367 BEAST_EXPECT(c1.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE == false);
1368 });
1369
1370 doTest("Test Config - squelch enabled", log, [&](bool log) {
1371 Config c;
1372
1373 std::string toLoad(R"rippleConfig(
1374[reduce_relay]
1375vp_base_squelch_enable=1
1376)rippleConfig");
1377
1378 c.loadFromString(toLoad);
1379 BEAST_EXPECT(c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE == true);
1380 });
1381
1382 doTest("Test Config - squelch disabled", log, [&](bool log) {
1383 Config c;
1384
1385 std::string toLoad(R"rippleConfig(
1386[reduce_relay]
1387vp_base_squelch_enable=0
1388)rippleConfig");
1389
1390 c.loadFromString(toLoad);
1391 BEAST_EXPECT(c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE == false);
1392 });
1393
1394 doTest("Test Config - legacy and new", log, [&](bool log) {
1395 Config c;
1396
1397 std::string toLoad(R"rippleConfig(
1398[reduce_relay]
1399vp_base_squelch_enable=0
1400vp_enable=0
1401)rippleConfig");
1402
1403 std::string error;
1404 auto const expectedError =
1405 "Invalid reduce_relay"
1406 " cannot specify both vp_base_squelch_enable and vp_enable "
1407 "options. "
1408 "vp_enable was deprecated and replaced by "
1409 "vp_base_squelch_enable";
1410
1411 try
1412 {
1413 c.loadFromString(toLoad);
1414 }
1415 catch (std::runtime_error& e)
1416 {
1417 error = e.what();
1418 }
1419
1420 BEAST_EXPECT(error == expectedError);
1421 });
1422
1423 doTest("Test Config - max selected peers", log, [&](bool log) {
1424 Config c;
1425
1426 std::string toLoad(R"rippleConfig(
1427[reduce_relay]
1428)rippleConfig");
1429
1430 c.loadFromString(toLoad);
1431 BEAST_EXPECT(c.VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS == 5);
1432
1433 Config c1;
1434
1435 toLoad = R"rippleConfig(
1436[reduce_relay]
1437vp_base_squelch_max_selected_peers=6
1438)rippleConfig";
1439
1440 c1.loadFromString(toLoad);
1441 BEAST_EXPECT(c1.VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS == 6);
1442
1443 Config c2;
1444
1445 toLoad = R"rippleConfig(
1446[reduce_relay]
1447vp_base_squelch_max_selected_peers=2
1448)rippleConfig";
1449
1450 std::string error;
1451 auto const expectedError =
1452 "Invalid reduce_relay"
1453 " vp_base_squelch_max_selected_peers must be "
1454 "greater than or equal to 3";
1455 try
1456 {
1457 c2.loadFromString(toLoad);
1458 }
1459 catch (std::runtime_error& e)
1460 {
1461 error = e.what();
1462 }
1463
1464 BEAST_EXPECT(error == expectedError);
1465 });
1466 }
1467
1468 void
1470 {
1471 doTest("BaseSquelchReady", log, [&](bool log) {
1472 ManualClock::reset();
1473 auto createSlots = [&](bool baseSquelchEnabled)
1475 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
1476 baseSquelchEnabled;
1478 env_.app().logs(), network_.overlay(), env_.app().config());
1479 };
1480 // base squelching must not be ready if squelching is disabled
1481 BEAST_EXPECT(!createSlots(false).baseSquelchReady());
1482
1483 // base squelch must not be ready as not enough time passed from
1484 // bootup
1485 BEAST_EXPECT(!createSlots(true).baseSquelchReady());
1486
1487 ManualClock::advance(reduce_relay::WAIT_ON_BOOTUP + minutes{1});
1488
1489 // base squelch enabled and bootup time passed
1490 BEAST_EXPECT(createSlots(true).baseSquelchReady());
1491
1492 // even if time passed, base squelching must not be ready if turned
1493 // off in the config
1494 BEAST_EXPECT(!createSlots(false).baseSquelchReady());
1495 });
1496 }
1497
1498 void
1500 {
1501 doTest("Duplicate Message", log, [&](bool log) {
1502 network_.reset();
1503 // update message count for the same peer/validator
1504 std::int16_t nMessages = 5;
1505 for (int i = 0; i < nMessages; i++)
1506 {
1507 uint256 key(i);
1508 network_.overlay().updateSlotAndSquelch(
1509 key,
1510 network_.validator(0),
1511 0,
1512 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1513 }
1514 auto peers = network_.overlay().getPeers(network_.validator(0));
1515 // first message changes Slot state to Counting and is not counted,
1516 // hence '-1'.
1517 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1518 // add duplicate
1519 uint256 key(nMessages - 1);
1520 network_.overlay().updateSlotAndSquelch(
1521 key,
1522 network_.validator(0),
1523 0,
1524 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1525 // confirm the same number of messages
1526 peers = network_.overlay().getPeers(network_.validator(0));
1527 BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1));
1528 // advance the clock
1529 ManualClock::advance(reduce_relay::IDLED + seconds(1));
1530 network_.overlay().updateSlotAndSquelch(
1531 key,
1532 network_.validator(0),
1533 0,
1534 [&](PublicKey const&, PeerWPtr, std::uint32_t) {});
1535 peers = network_.overlay().getPeers(network_.validator(0));
1536 // confirm message number increased
1537 BEAST_EXPECT(std::get<1>(peers[0]) == nMessages);
1538 });
1539 }
1540
1542 {
1543 Handler() : maxDuration_(0)
1544 {
1545 }
1546 void
1548 const override
1549 {
1550 if (duration > maxDuration_)
1551 maxDuration_ = duration;
1552 }
1553 void
1554 unsquelch(PublicKey const&, Peer::id_t) const override
1555 {
1556 }
1557 mutable int maxDuration_;
1558 };
1559
1560 void
1562 {
1563 doTest("Random Squelch", l, [&](bool l) {
1565 Handler handler;
1566
1567 auto run = [&](int npeers) {
1568 handler.maxDuration_ = 0;
1570 env_.app().logs(), handler, env_.app().config());
1571 // 1st message from a new peer switches the slot
1572 // to counting state and resets the counts of all peers +
1573 // MAX_MESSAGE_THRESHOLD + 1 messages to reach the threshold
1574 // and switch the slot's state to peer selection.
1575 for (int m = 1; m <= reduce_relay::MAX_MESSAGE_THRESHOLD + 2;
1576 m++)
1577 {
1578 for (int peer = 0; peer < npeers; peer++)
1579 {
1580 // make unique message hash to make the
1581 // slot's internal hash router accept the message
1582 std::uint64_t mid = m * 1000 + peer;
1583 uint256 const message{mid};
1585 message,
1586 validator,
1587 peer,
1588 protocol::MessageType::mtVALIDATION);
1589 }
1590 }
1591 // make Slot's internal hash router expire all messages
1592 ManualClock::advance(hours(1));
1593 };
1594
1595 using namespace reduce_relay;
1596 // expect max duration less than MAX_UNSQUELCH_EXPIRE_DEFAULT with
1597 // less than or equal to 60 peers
1598 run(20);
1599 BEAST_EXPECT(
1600 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1601 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1602 run(60);
1603 BEAST_EXPECT(
1604 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1605 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count());
1606 // expect max duration greater than MIN_UNSQUELCH_EXPIRE and less
1607 // than MAX_UNSQUELCH_EXPIRE_PEERS with peers greater than 60
1608 // and less than 360
1609 run(350);
1610 // can't make this condition stronger. squelch
1611 // duration is probabilistic and max condition may still fail.
1612 // log when the value is low
1613 BEAST_EXPECT(
1614 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1615 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1616 using namespace beast::unit_test::detail;
1617 if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1618 log << make_reason(
1619 "warning: squelch duration is low",
1620 __FILE__,
1621 __LINE__)
1622 << std::endl
1623 << std::flush;
1624 // more than 400 is still less than MAX_UNSQUELCH_EXPIRE_PEERS
1625 run(400);
1626 BEAST_EXPECT(
1627 handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() &&
1628 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count());
1629 if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count())
1630 log << make_reason(
1631 "warning: squelch duration is low",
1632 __FILE__,
1633 __LINE__)
1634 << std::endl
1635 << std::flush;
1636 });
1637 }
1638
1639 void
1641 {
1642 doTest("Handshake", log, [&](bool log) {
1643 auto setEnv = [&](bool enable) {
1644 Config c;
1646 str << "[reduce_relay]\n"
1647 << "vp_enable=" << enable << "\n"
1648 << "[compression]\n"
1649 << "1\n";
1650 c.loadFromString(str.str());
1651 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE =
1653
1654 env_.app().config().COMPRESSION = c.COMPRESSION;
1655 };
1656 auto handshake = [&](int outboundEnable, int inboundEnable) {
1657 beast::IP::Address addr =
1658 boost::asio::ip::make_address("172.1.1.100");
1659
1660 setEnv(outboundEnable);
1661 auto request = ripple::makeRequest(
1662 true,
1663 env_.app().config().COMPRESSION,
1664 false,
1665 env_.app().config().TX_REDUCE_RELAY_ENABLE,
1666 env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE);
1667 http_request_type http_request;
1668 http_request.version(request.version());
1669 http_request.base() = request.base();
1670 // feature enabled on the peer's connection only if both sides
1671 // are enabled
1672 auto const peerEnabled = inboundEnable && outboundEnable;
1673 // inbound is enabled if the request's header has the feature
1674 // enabled and the peer's configuration is enabled
1675 auto const inboundEnabled = peerFeatureEnabled(
1676 http_request, FEATURE_VPRR, inboundEnable);
1677 BEAST_EXPECT(!(peerEnabled ^ inboundEnabled));
1678
1679 setEnv(inboundEnable);
1680 auto http_resp = ripple::makeResponse(
1681 true,
1682 http_request,
1683 addr,
1684 addr,
1685 uint256{1},
1686 1,
1687 {1, 0},
1688 env_.app());
1689 // outbound is enabled if the response's header has the feature
1690 // enabled and the peer's configuration is enabled
1691 auto const outboundEnabled =
1692 peerFeatureEnabled(http_resp, FEATURE_VPRR, outboundEnable);
1693 BEAST_EXPECT(!(peerEnabled ^ outboundEnabled));
1694 };
1695 handshake(1, 1);
1696 handshake(1, 0);
1697 handshake(0, 1);
1698 handshake(0, 0);
1699 });
1700 }
1701
1704
1705public:
1707 : env_(*this, jtx::envconfig([](std::unique_ptr<Config> cfg) {
1708 cfg->VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = true;
1709 cfg->VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS = 6;
1710 return cfg;
1711 }))
1712 , network_(env_.app())
1713 {
1714 }
1715
1716 void
1717 run() override
1718 {
1719 bool log = false;
1720 testConfig(log);
1721 testInitialRound(log);
1722 testPeerUnsquelchedTooSoon(log);
1723 testPeerUnsquelched(log);
1724 testNewPeer(log);
1725 testSquelchedPeerDisconnects(log);
1726 testSelectedPeerDisconnects(log);
1727 testSelectedPeerStopsRelaying(log);
1728 testInternalHashRouter(log);
1729 testRandomSquelch(log);
1730 testHandshake(log);
1731 testBaseSquelchReady(log);
1732 }
1733};
1734
1736{
1737 void
1738 testRandom(bool log)
1739 {
1740 doTest("Random Test", log, [&](bool log) { random(log); });
1741 }
1742
1743 void
1744 run() override
1745 {
1746 bool log = false;
1747 testRandom(log);
1748 }
1749};
1750
1751BEAST_DEFINE_TESTSUITE(reduce_relay, overlay, ripple);
1752BEAST_DEFINE_TESTSUITE_MANUAL(reduce_relay_simulate, overlay, ripple);
1753
1754} // namespace test
1755
1756} // namespace ripple
T back_inserter(T... args)
T begin(T... args)
Represents a JSON value.
Definition json_value.h:149
A version-independent IP address and port combination.
Definition IPEndpoint.h:38
A generic endpoint for log messages.
Definition Journal.h:60
A testsuite class.
Definition suite.h:55
log_os< char > log
Logging output stream.
Definition suite.h:152
virtual Config & config()=0
bool VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE
Definition Config.h:248
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition Config.cpp:479
bool COMPRESSION
Definition Config.h:220
std::size_t VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS
Definition Config.h:254
Manages partitions for logging.
Definition Log.h:52
beast::Journal journal(std::string const &name)
Definition Log.cpp:160
Represents a peer connection in the overlay.
std::uint32_t id_t
Uniquely identifies a peer.
A public key.
Definition PublicKey.h:61
std::uint8_t const * data() const noexcept
Definition PublicKey.h:86
std::size_t size() const noexcept
Definition PublicKey.h:92
A consumption charge.
Definition Charge.h:30
An immutable linear range of bytes.
Definition Slice.h:46
Slot is associated with a specific validator via validator's public key.
Slots is a container for validator's Slot and handles Slot update when a message is received from a v...
void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, id_t id, protocol::MessageType type)
Calls Slot::update of Slot associated with the validator, with a noop callback.
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.
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
void removeTxQueue(uint256 const &) override
Remove hash from the transactions' hashes queue.
std::optional< std::size_t > publisherListSequence(PublicKey const &) const override
void send(protocol::TMSquelch const &squelch)
bool txReduceRelayEnabled() const override
void addTxQueue(uint256 const &) 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
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.
Validator & operator=(Validator const &)=default
A transaction testing environment.
Definition Env.h:121
Application & app()
Definition Env.h:261
Set the fee on a JTx.
Definition fee.h:37
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 testInitialRound(bool log)
Initial counting round: three peers receive message "faster" then others.
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.
void printPeers(std::string const &msg, std::uint16_t validator=0)
void doTest(std::string const &msg, bool log, std::function< void(bool)> f)
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 is_same_v
T lock(T... args)
T make_pair(T... args)
boost::asio::ip::address Address
Definition IPAddress.h:39
static constexpr auto IDLED
PeerState
Peer's State.
static constexpr uint16_t MAX_MESSAGE_THRESHOLD
static constexpr auto WAIT_ON_BOOTUP
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:54
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:25
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
http_response_type makeResponse(bool crawlPublic, http_request_type const &req, beast::IP::Address public_ip, beast::IP::Address remote_ip, uint256 const &sharedValue, std::optional< std::uint32_t > networkID, ProtocolVersion protocol, Application &app)
Make http response.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
int run(int argc, char **argv)
Definition Main.cpp:349
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
KeyType
Definition KeyType.h:28
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:33
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:198
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
constexpr Number squelch(Number const &x, Number const &limit) noexcept
Definition Number.h:381
static constexpr char FEATURE_VPRR[]
Definition Handshake.h:143
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)
T what(T... args)