rippled
Loading...
Searching...
No Matches
LedgerReplay_test.cpp
1#include <test/jtx.h>
2#include <test/jtx/envconfig.h>
3
4#include <xrpld/app/ledger/BuildLedger.h>
5#include <xrpld/app/ledger/LedgerMaster.h>
6#include <xrpld/app/ledger/LedgerReplay.h>
7#include <xrpld/app/ledger/LedgerReplayTask.h>
8#include <xrpld/app/ledger/LedgerReplayer.h>
9#include <xrpld/app/ledger/detail/LedgerDeltaAcquire.h>
10#include <xrpld/app/ledger/detail/LedgerReplayMsgHandler.h>
11#include <xrpld/app/ledger/detail/SkipListAcquire.h>
12#include <xrpld/overlay/PeerSet.h>
13#include <xrpld/overlay/detail/PeerImp.h>
14
15#include <xrpl/basics/Slice.h>
16
17#include <chrono>
18#include <thread>
19
20namespace xrpl {
21namespace test {
22
24{
25 void
26 run() override
27 {
28 testcase("Replay ledger");
29
30 using namespace jtx;
31
32 // Build a ledger normally
33 auto const alice = Account("alice");
34 auto const bob = Account("bob");
35
36 Env env(*this);
37 env.fund(XRP(100000), alice, bob);
38 env.close();
39
41 auto const lastClosed = ledgerMaster.getClosedLedger();
42 auto const lastClosedParent =
43 ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
44
45 auto const replayed = buildLedger(
46 LedgerReplay(lastClosedParent, lastClosed),
47 tapNONE,
48 env.app(),
49 env.journal);
50
51 BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
52 }
53};
54
56 Good,
57 DropAll,
58};
59
66{
67public:
75 virtual ~MagicInboundLedgers() = default;
76
79 override
80 {
82 return {};
83 if (auto l = ledgerSource.getLedgerByHash(hash); l)
84 {
86 return l;
87 }
88
89 return {};
90 }
91
92 virtual void
94 uint256 const& hash,
96 InboundLedger::Reason reason) override
97 {
98 }
99
101 find(LedgerHash const& hash) override
102 {
103 return {};
104 }
105
106 virtual bool
108 LedgerHash const& ledgerHash,
111 {
112 return false;
113 }
114
115 virtual void
119
120 virtual void
122 {
123 }
124
125 virtual bool
126 isFailure(uint256 const& h) override
127 {
128 return false;
129 }
130
131 virtual void
132 clearFailures() override
133 {
134 }
135
136 virtual Json::Value
137 getInfo() override
138 {
139 return {};
140 }
141
142 virtual std::size_t
143 fetchRate() override
144 {
145 return 0;
146 }
147
148 virtual void
150 {
151 }
152
153 virtual void
154 gotFetchPack() override
155 {
156 }
157 virtual void
158 sweep() override
159 {
160 }
161
162 virtual void
163 stop() override
164 {
165 }
166
167 virtual size_t
168 cacheSize() override
169 {
170 return 0;
171 }
172
176};
177
178enum class PeerFeature {
180 None,
181};
182
188class TestPeer : public Peer
189{
190public:
191 TestPeer(bool enableLedgerReplay)
192 : ledgerReplayEnabled_(enableLedgerReplay)
194 {
195 }
196
197 void
199 {
200 }
202 getRemoteAddress() const override
203 {
204 return {};
205 }
206 void
207 charge(Resource::Charge const& fee, std::string const& context = {})
208 override
209 {
210 }
211 id_t
212 id() const override
213 {
214 return 1234;
215 }
216 bool
217 cluster() const override
218 {
219 return false;
220 }
221 bool
222 isHighLatency() const override
223 {
224 return false;
225 }
226 int
227 getScore(bool) const override
228 {
229 return 0;
230 }
231 PublicKey const&
232 getNodePublic() const override
233 {
234 return nodePublicKey_;
235 }
237 json() override
238 {
239 return {};
240 }
241 bool
243 {
245 return true;
246 return false;
247 }
249 publisherListSequence(PublicKey const&) const override
250 {
251 return {};
252 }
253 void
255 {
256 }
257 uint256 const&
258 getClosedLedgerHash() const override
259 {
260 static uint256 hash{};
261 return hash;
262 }
263 bool
264 hasLedger(uint256 const& hash, std::uint32_t seq) const override
265 {
266 return true;
267 }
268 void
269 ledgerRange(std::uint32_t& minSeq, std::uint32_t& maxSeq) const override
270 {
271 }
272 bool
273 hasTxSet(uint256 const& hash) const override
274 {
275 return false;
276 }
277 void
278 cycleStatus() override
279 {
280 }
281 bool
283 {
284 return false;
285 }
286 bool
287 compressionEnabled() const override
288 {
289 return false;
290 }
291 void
292 sendTxQueue() override
293 {
294 }
295 void
296 addTxQueue(uint256 const&) override
297 {
298 }
299 void
300 removeTxQueue(uint256 const&) override
301 {
302 }
303 bool
304 txReduceRelayEnabled() const override
305 {
306 return false;
307 }
308
309 std::string const&
310 fingerprint() const override
311 {
312 return fingerprint_;
313 }
314
318};
319
320enum class PeerSetBehavior {
321 Good,
322 Drop50,
323 DropAll,
326 Repeat,
327};
328
335struct TestPeerSet : public PeerSet
336{
340 PeerSetBehavior bhvr,
341 bool enableLedgerReplay)
342 : local(me)
343 , remote(other)
344 , dummyPeer(std::make_shared<TestPeer>(enableLedgerReplay))
345 , behavior(bhvr)
346 {
347 }
348
349 void
351 std::size_t limit,
352 std::function<bool(std::shared_ptr<Peer> const&)> hasItem,
353 std::function<void(std::shared_ptr<Peer> const&)> onPeerAdded) override
354 {
355 hasItem(dummyPeer);
356 onPeerAdded(dummyPeer);
357 }
358
359 void
361 ::google::protobuf::Message const& msg,
362 protocol::MessageType type,
363 std::shared_ptr<Peer> const& peer) override
364 {
365 int dropRate = 0;
367 dropRate = 50;
369 dropRate = 100;
370
371 if ((rand() % 100 + 1) <= dropRate)
372 return;
373
374 switch (type)
375 {
376 case protocol::mtPROOF_PATH_REQ: {
378 return;
380 dynamic_cast<protocol::TMProofPathRequest const&>(msg));
386 break;
387 }
388 case protocol::mtREPLAY_DELTA_REQ: {
390 return;
392 dynamic_cast<protocol::TMReplayDeltaRequest const&>(msg));
398 break;
399 }
400 default:
401 return;
402 }
403 }
404
406 getPeerIds() const override
407 {
408 static std::set<Peer::id_t> emptyPeers;
409 return emptyPeers;
410 }
411
416};
417
449
455{
457 {
459 int initAccounts = 10;
460 int initAmount = 1'000'000;
462 int txAmount = 10;
463 };
464
466 : env(suite)
467 , app(env.app())
468 , ledgerMaster(env.app().getLedgerMaster())
469 , msgHandler(env.app(), env.app().getLedgerReplayer())
470 , param(p)
471 {
472 assert(param.initLedgers > 0);
476 }
477
481 void
482 createAccounts(int newAccounts)
483 {
484 auto fundedAccounts = accounts.size();
485 for (int i = 0; i < newAccounts; ++i)
486 {
487 accounts.emplace_back(
488 "alice_" + std::to_string(fundedAccounts + i));
490 }
491 env.close();
492 }
493
497 void
498 sendPayments(int newTxes)
499 {
500 int fundedAccounts = accounts.size();
501 assert(fundedAccounts >= newTxes);
503
504 // somewhat random but reproducible
505 int r = ledgerMaster.getClosedLedger()->seq() * 7;
506 int fromIdx = 0;
507 int toIdx = 0;
508 auto updateIdx = [&]() {
509 assert(fundedAccounts > senders.size());
510 fromIdx = (fromIdx + r) % fundedAccounts;
511 while (senders.count(fromIdx) != 0)
512 fromIdx = (fromIdx + 1) % fundedAccounts;
513 senders.insert(fromIdx);
514 toIdx = (toIdx + r * 2) % fundedAccounts;
515 if (toIdx == fromIdx)
516 toIdx = (toIdx + 1) % fundedAccounts;
517 };
518
519 for (int i = 0; i < newTxes; ++i)
520 {
521 updateIdx();
522 env.apply(
523 pay(accounts[fromIdx],
524 accounts[toIdx],
525 jtx::drops(ledgerMaster.getClosedLedger()->fees().base) +
530 }
531 env.close();
532 }
533
537 void
539 {
540 for (int i = 0; i < param.initLedgers - 1; ++i)
541 {
543 }
544 }
545
552};
553
554enum class TaskStatus {
555 Failed,
556 Completed,
557 NotDone,
558 NotExist,
559};
560
569{
570public:
573 LedgerServer& server,
577 : env(suite, jtx::envconfig(), nullptr, beast::severities::kDisabled)
578 , app(env.app())
579 , ledgerMaster(env.app().getLedgerMaster())
581 server.app.getLedgerMaster(),
583 inboundBhvr)
584 , serverMsgHandler(server.app, server.app.getLedgerReplayer())
586 , replayer(
587 env.app(),
589 std::make_unique<TestPeerSetBuilder>(
592 behavior,
593 peerFeature))
594 {
595 }
596
597 void
602
603 bool
604 haveLedgers(uint256 const& finishLedgerHash, int totalReplay)
605 {
606 uint256 hash = finishLedgerHash;
607 int i = 0;
608 for (; i < totalReplay; ++i)
609 {
610 auto const l = ledgerMaster.getLedgerByHash(hash);
611 if (!l)
612 return false;
613 hash = l->header().parentHash;
614 }
615 return true;
616 }
617
618 bool
619 waitForLedgers(uint256 const& finishLedgerHash, int totalReplay)
620 {
621 int totalRound = 100;
622 for (int i = 0; i < totalRound; ++i)
623 {
624 if (haveLedgers(finishLedgerHash, totalReplay))
625 return true;
626 if (i < totalRound - 1)
628 }
629 return false;
630 }
631
632 bool
634 {
635 int totalRound = 100;
636 for (int i = 0; i < totalRound; ++i)
637 {
638 bool allDone = true;
639 {
641 for (auto const& t : replayer.tasks_)
642 {
643 if (!t->finished())
644 {
645 allDone = false;
646 break;
647 }
648 }
649 }
650 if (allDone)
651 return true;
652 if (i < totalRound - 1)
654 }
655 return false;
656 }
657
660 {
662 return replayer.tasks_;
663 }
664
666 findTask(uint256 const& hash, int totalReplay)
667 {
669 auto i = std::find_if(
670 replayer.tasks_.begin(), replayer.tasks_.end(), [&](auto const& t) {
671 return t->parameter_.finishHash_ == hash &&
672 t->parameter_.totalLedgers_ == totalReplay;
673 });
674 if (i == replayer.tasks_.end())
675 return {};
676 return *i;
677 }
678
681 {
683 return replayer.deltas_.size();
684 }
685
688 {
690 return replayer.skipLists_.size();
691 }
692
693 bool
695 std::size_t tasks,
696 std::size_t skipLists,
697 std::size_t deltas)
698 {
700 return replayer.tasks_.size() == tasks &&
701 replayer.skipLists_.size() == skipLists &&
702 replayer.deltas_.size() == deltas;
703 }
704
707 {
709 auto i = replayer.skipLists_.find(hash);
710 if (i == replayer.skipLists_.end())
711 return {};
712 return i->second.lock();
713 }
714
717 {
719 auto i = replayer.deltas_.find(hash);
720 if (i == replayer.deltas_.end())
721 return {};
722 return i->second.lock();
723 }
724
725 template <typename T>
728 {
729 if (t->failed_)
730 return TaskStatus::Failed;
731 if (t->complete_)
733 return TaskStatus::NotDone;
734 }
735
736 bool
739 TaskStatus taskExpect,
740 TaskStatus skiplistExpect,
741 std::vector<TaskStatus> const& deltaExpects)
742 {
743 if (taskStatus(task) == taskExpect)
744 {
745 if (taskStatus(task->skipListAcquirer_) == skiplistExpect)
746 {
747 if (task->deltas_.size() == deltaExpects.size())
748 {
749 for (int i = 0; i < deltaExpects.size(); ++i)
750 {
751 if (taskStatus(task->deltas_[i]) != deltaExpects[i])
752 return false;
753 }
754 return true;
755 }
756 }
757 }
758 return false;
759 }
760
761 bool
763 uint256 const& hash,
764 int totalReplay,
765 TaskStatus taskExpect,
766 TaskStatus skiplistExpect,
767 std::vector<TaskStatus> const& deltaExpects)
768 {
769 auto t = findTask(hash, totalReplay);
770 if (!t)
771 {
772 if (taskExpect == TaskStatus::NotExist)
773 return true;
774 return false;
775 }
776
777 return asExpected(t, taskExpect, skiplistExpect, deltaExpects);
778 }
779
780 bool
782 uint256 const& hash,
783 int totalReplay,
784 TaskStatus taskExpect,
785 TaskStatus skiplistExpect,
786 std::vector<TaskStatus> const& deltaExpects)
787 {
788 auto t = findTask(hash, totalReplay);
789 if (!t)
790 {
791 if (taskExpect == TaskStatus::NotExist)
792 return true;
793 return false;
794 }
795
796 return asExpected(t, taskExpect, skiplistExpect, deltaExpects);
797 }
798
799 bool
801 uint256 const& hash,
802 int totalReplay,
803 TaskStatus taskExpect,
804 TaskStatus skiplistExpect,
805 std::vector<TaskStatus> const& deltaExpects)
806 {
807 if (!waitForDone())
808 return false;
809
810 return checkStatus(
811 hash, totalReplay, taskExpect, skiplistExpect, deltaExpects);
812 }
813
821};
822
823using namespace beast::severities;
824void
826 LedgerServer& server,
827 LedgerReplayClient& client,
828 beast::severities::Severity level = Severity::kTrace)
829{
830 server.app.logs().threshold(level);
831 client.app.logs().threshold(level);
832}
833// logAll(net.server, net.client);
834
835/*
836 * Create a LedgerServer and a LedgerReplayClient
837 */
839{
842 LedgerServer::Parameter const& param,
846 : server(suite, param)
847 , client(suite, server, behavior, inboundBhvr, peerFeature)
848 {
849 // logAll(server, client);
850 }
853};
854
881{
882 void
884 {
885 testcase("ProofPath");
886 LedgerServer server(*this, {1});
887 auto const l = server.ledgerMaster.getClosedLedger();
888
889 {
890 // request, missing key
892 request->set_ledgerhash(
893 l->header().hash.data(), l->header().hash.size());
894 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
896 server.msgHandler.processProofPathRequest(request));
897 BEAST_EXPECT(reply->has_error());
898 BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply));
899 }
900 {
901 // request, wrong hash
903 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
904 request->set_key(
905 keylet::skip().key.data(), keylet::skip().key.size());
906 uint256 hash(1234567);
907 request->set_ledgerhash(hash.data(), hash.size());
909 server.msgHandler.processProofPathRequest(request));
910 BEAST_EXPECT(reply->has_error());
911 }
912
913 {
914 // good request
916 request->set_ledgerhash(
917 l->header().hash.data(), l->header().hash.size());
918 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
919 request->set_key(
920 keylet::skip().key.data(), keylet::skip().key.size());
921 // generate response
923 server.msgHandler.processProofPathRequest(request));
924 BEAST_EXPECT(!reply->has_error());
925 BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply));
926
927 {
928 // bad reply
929 // bad header
930 std::string r(reply->ledgerheader());
931 r.back()--;
932 reply->set_ledgerheader(r);
933 BEAST_EXPECT(
934 !server.msgHandler.processProofPathResponse(reply));
935 r.back()++;
936 reply->set_ledgerheader(r);
937 BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply));
938 // bad proof path
939 reply->mutable_path()->RemoveLast();
940 BEAST_EXPECT(
941 !server.msgHandler.processProofPathResponse(reply));
942 }
943 }
944 }
945
946 void
948 {
949 testcase("ReplayDelta");
950 LedgerServer server(*this, {1});
951 auto const l = server.ledgerMaster.getClosedLedger();
952
953 {
954 // request, missing hash
957 server.msgHandler.processReplayDeltaRequest(request));
958 BEAST_EXPECT(reply->has_error());
959 BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
960 // request, wrong hash
961 uint256 hash(1234567);
962 request->set_ledgerhash(hash.data(), hash.size());
964 server.msgHandler.processReplayDeltaRequest(request));
965 BEAST_EXPECT(reply->has_error());
966 BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
967 }
968
969 {
970 // good request
972 request->set_ledgerhash(
973 l->header().hash.data(), l->header().hash.size());
975 server.msgHandler.processReplayDeltaRequest(request));
976 BEAST_EXPECT(!reply->has_error());
977 BEAST_EXPECT(server.msgHandler.processReplayDeltaResponse(reply));
978
979 {
980 // bad reply
981 // bad header
982 std::string r(reply->ledgerheader());
983 r.back()--;
984 reply->set_ledgerheader(r);
985 BEAST_EXPECT(
986 !server.msgHandler.processReplayDeltaResponse(reply));
987 r.back()++;
988 reply->set_ledgerheader(r);
989 BEAST_EXPECT(
990 server.msgHandler.processReplayDeltaResponse(reply));
991 // bad txns
992 reply->mutable_transaction()->RemoveLast();
993 BEAST_EXPECT(
994 !server.msgHandler.processReplayDeltaResponse(reply));
995 }
996 }
997 }
998
999 void
1001 {
1002 testcase("TaskParameter");
1003
1004 auto makeSkipList = [](int count) -> std::vector<uint256> const {
1006 for (int i = 0; i < count; ++i)
1007 sList.emplace_back(i);
1008 return sList;
1009 };
1010
1013 BEAST_EXPECT(!tp10.update(uint256(777), 5, makeSkipList(10)));
1014 BEAST_EXPECT(!tp10.update(uint256(10), 5, makeSkipList(8)));
1015 BEAST_EXPECT(tp10.update(uint256(10), 10, makeSkipList(10)));
1016
1017 // can merge to self
1018 BEAST_EXPECT(tp10.canMergeInto(tp10));
1019
1020 // smaller task
1023
1024 BEAST_EXPECT(tp9.canMergeInto(tp10));
1025 BEAST_EXPECT(!tp10.canMergeInto(tp9));
1026
1027 tp9.totalLedgers_++;
1028 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1029 tp9.totalLedgers_--;
1030 BEAST_EXPECT(tp9.canMergeInto(tp10));
1031
1033 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1035 BEAST_EXPECT(tp9.canMergeInto(tp10));
1036
1037 tp9.finishHash_ = uint256(1234);
1038 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1039 tp9.finishHash_ = uint256(9);
1040 BEAST_EXPECT(tp9.canMergeInto(tp10));
1041
1042 // larger task
1045 BEAST_EXPECT(tp20.update(uint256(20), 20, makeSkipList(20)));
1046 BEAST_EXPECT(tp10.canMergeInto(tp20));
1047 BEAST_EXPECT(tp9.canMergeInto(tp20));
1048 BEAST_EXPECT(!tp20.canMergeInto(tp10));
1049 BEAST_EXPECT(!tp20.canMergeInto(tp9));
1050 }
1051
1052 void
1054 {
1055 testcase("config test");
1056 {
1057 Config c;
1058 BEAST_EXPECT(c.LEDGER_REPLAY == false);
1059 }
1060
1061 {
1062 Config c;
1063 std::string toLoad(R"rippleConfig(
1064[ledger_replay]
10651
1066)rippleConfig");
1067 c.loadFromString(toLoad);
1068 BEAST_EXPECT(c.LEDGER_REPLAY == true);
1069 }
1070
1071 {
1072 Config c;
1073 std::string toLoad = (R"rippleConfig(
1074[ledger_replay]
10750
1076)rippleConfig");
1077 c.loadFromString(toLoad);
1078 BEAST_EXPECT(c.LEDGER_REPLAY == false);
1079 }
1080 }
1081
1082 void
1084 {
1085 testcase("handshake test");
1086 auto handshake = [&](bool client, bool server, bool expecting) -> bool {
1087 auto request = xrpl::makeRequest(true, false, client, false, false);
1088 http_request_type http_request;
1089 http_request.version(request.version());
1090 http_request.base() = request.base();
1091 bool serverResult =
1092 peerFeatureEnabled(http_request, FEATURE_LEDGER_REPLAY, server);
1093 if (serverResult != expecting)
1094 return false;
1095
1096 beast::IP::Address addr =
1097 boost::asio::ip::make_address("172.1.1.100");
1098 jtx::Env serverEnv(*this);
1099 serverEnv.app().config().LEDGER_REPLAY = server;
1100 auto http_resp = xrpl::makeResponse(
1101 true,
1102 http_request,
1103 addr,
1104 addr,
1105 uint256{1},
1106 1,
1107 {1, 0},
1108 serverEnv.app());
1109 auto const clientResult =
1110 peerFeatureEnabled(http_resp, FEATURE_LEDGER_REPLAY, client);
1111 if (clientResult != expecting)
1112 return false;
1113
1114 return true;
1115 };
1116
1117 BEAST_EXPECT(handshake(false, false, false));
1118 BEAST_EXPECT(handshake(false, true, false));
1119 BEAST_EXPECT(handshake(true, false, false));
1120 BEAST_EXPECT(handshake(true, true, true));
1121 }
1122
1123 void
1124 testAllLocal(int totalReplay)
1125 {
1126 testcase("local node has all the ledgers");
1127 auto psBhvr = PeerSetBehavior::DropAll;
1128 auto ilBhvr = InboundLedgersBehavior::DropAll;
1129 auto peerFeature = PeerFeature::None;
1130
1131 NetworkOfTwo net(*this, {totalReplay + 1}, psBhvr, ilBhvr, peerFeature);
1132
1133 auto l = net.server.ledgerMaster.getClosedLedger();
1134 uint256 finalHash = l->header().hash;
1135 for (int i = 0; i < totalReplay; ++i)
1136 {
1137 BEAST_EXPECT(l);
1138 if (l)
1139 {
1140 net.client.ledgerMaster.storeLedger(l);
1141 l = net.server.ledgerMaster.getLedgerByHash(
1142 l->header().parentHash);
1143 }
1144 else
1145 break;
1146 }
1147
1148 net.client.replayer.replay(
1149 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1150
1151 std::vector<TaskStatus> deltaStatuses(
1152 totalReplay - 1, TaskStatus::Completed);
1153 BEAST_EXPECT(net.client.waitAndCheckStatus(
1154 finalHash,
1155 totalReplay,
1158 deltaStatuses));
1159
1160 // sweep
1161 net.client.replayer.sweep();
1162 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1163 }
1164
1165 void
1166 testAllInboundLedgers(int totalReplay)
1167 {
1168 testcase("all the ledgers from InboundLedgers");
1169 NetworkOfTwo net(
1170 *this,
1171 {totalReplay + 1},
1175
1176 auto l = net.server.ledgerMaster.getClosedLedger();
1177 uint256 finalHash = l->header().hash;
1178 net.client.replayer.replay(
1179 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1180
1181 std::vector<TaskStatus> deltaStatuses(
1182 totalReplay - 1, TaskStatus::Completed);
1183 BEAST_EXPECT(net.client.waitAndCheckStatus(
1184 finalHash,
1185 totalReplay,
1188 deltaStatuses));
1189
1190 // sweep
1191 net.client.replayer.sweep();
1192 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1193 }
1194
1195 void
1196 testPeerSetBehavior(PeerSetBehavior peerSetBehavior, int totalReplay = 4)
1197 {
1198 switch (peerSetBehavior)
1199 {
1201 testcase("good network");
1202 break;
1204 testcase("network drops 50% messages");
1205 break;
1207 testcase("network repeats all messages");
1208 break;
1209 default:
1210 return;
1211 }
1212
1213 NetworkOfTwo net(
1214 *this,
1215 {totalReplay + 1},
1216 peerSetBehavior,
1219
1220 // feed client with start ledger since InboundLedgers drops all
1221 auto l = net.server.ledgerMaster.getClosedLedger();
1222 uint256 finalHash = l->header().hash;
1223 for (int i = 0; i < totalReplay - 1; ++i)
1224 {
1225 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1226 }
1227 net.client.ledgerMaster.storeLedger(l);
1228
1229 net.client.replayer.replay(
1230 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1231
1232 std::vector<TaskStatus> deltaStatuses(
1233 totalReplay - 1, TaskStatus::Completed);
1234 BEAST_EXPECT(net.client.waitAndCheckStatus(
1235 finalHash,
1236 totalReplay,
1239 deltaStatuses));
1240 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay));
1241
1242 // sweep
1243 net.client.replayer.sweep();
1244 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1245 }
1246
1247 void
1249 {
1250 testcase("stop before timeout");
1251 int totalReplay = 3;
1252 NetworkOfTwo net(
1253 *this,
1254 {totalReplay + 1},
1258
1259 auto l = net.server.ledgerMaster.getClosedLedger();
1260 uint256 finalHash = l->header().hash;
1261 net.client.replayer.replay(
1262 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1263
1264 std::vector<TaskStatus> deltaStatuses;
1265 BEAST_EXPECT(net.client.checkStatus(
1266 finalHash,
1267 totalReplay,
1270 deltaStatuses));
1271
1272 BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0));
1273 net.client.replayer.stop();
1274 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1275 }
1276
1277 void
1279 {
1280 testcase("SkipListAcquire bad reply");
1281 int totalReplay = 3;
1282 NetworkOfTwo net(
1283 *this,
1284 {totalReplay + 1 + 1},
1288
1289 auto l = net.server.ledgerMaster.getClosedLedger();
1290 uint256 finalHash = l->header().hash;
1291 net.client.replayer.replay(
1292 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1293
1294 auto skipList = net.client.findSkipListAcquire(finalHash);
1295
1296 std::uint8_t payload[55] = {
1297 0x6A, 0x09, 0xE6, 0x67, 0xF3, 0xBC, 0xC9, 0x08, 0xB2};
1298 auto item =
1299 make_shamapitem(uint256(12345), Slice(payload, sizeof(payload)));
1300 skipList->processData(l->seq(), item);
1301
1302 std::vector<TaskStatus> deltaStatuses;
1303 BEAST_EXPECT(net.client.waitAndCheckStatus(
1304 finalHash,
1305 totalReplay,
1308 deltaStatuses));
1309
1310 // add another task
1311 net.client.replayer.replay(
1312 InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1);
1313 BEAST_EXPECT(net.client.waitAndCheckStatus(
1314 finalHash,
1315 totalReplay,
1318 deltaStatuses));
1319 BEAST_EXPECT(net.client.countsAsExpected(2, 1, 0));
1320 }
1321
1322 void
1324 {
1325 testcase("LedgerDeltaAcquire bad reply");
1326 int totalReplay = 3;
1327 NetworkOfTwo net(
1328 *this,
1329 {totalReplay + 1},
1333
1334 auto l = net.server.ledgerMaster.getClosedLedger();
1335 uint256 finalHash = l->header().hash;
1336 net.client.ledgerMaster.storeLedger(l);
1337 net.client.replayer.replay(
1338 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1339
1340 auto delta = net.client.findLedgerDeltaAcquire(l->header().parentHash);
1341 delta->processData(
1342 l->header(), // wrong ledger info
1344 BEAST_EXPECT(net.client.taskStatus(delta) == TaskStatus::Failed);
1345 BEAST_EXPECT(
1346 net.client.taskStatus(net.client.findTask(
1347 finalHash, totalReplay)) == TaskStatus::Failed);
1348
1349 // add another task
1350 net.client.replayer.replay(
1351 InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1);
1352 BEAST_EXPECT(
1353 net.client.taskStatus(net.client.findTask(
1354 finalHash, totalReplay + 1)) == TaskStatus::Failed);
1355 }
1356
1357 void
1359 {
1360 testcase("Overlap tasks");
1361 int totalReplay = 5;
1362 NetworkOfTwo net(
1363 *this,
1364 {totalReplay * 3 + 1},
1368 auto l = net.server.ledgerMaster.getClosedLedger();
1369 uint256 finalHash = l->header().hash;
1370 net.client.replayer.replay(
1371 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1372 std::vector<TaskStatus> deltaStatuses(
1373 totalReplay - 1, TaskStatus::Completed);
1374 BEAST_EXPECT(net.client.waitAndCheckStatus(
1375 finalHash,
1376 totalReplay,
1379 deltaStatuses));
1380 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay));
1381
1382 // same range, same reason
1383 net.client.replayer.replay(
1384 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1385 BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1));
1386 // same range, different reason
1387 net.client.replayer.replay(
1388 InboundLedger::Reason::CONSENSUS, finalHash, totalReplay);
1389 BEAST_EXPECT(net.client.countsAsExpected(2, 1, totalReplay - 1));
1390
1391 // no overlap
1392 for (int i = 0; i < totalReplay + 2; ++i)
1393 {
1394 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1395 }
1396 auto finalHash_early = l->header().hash;
1397 net.client.replayer.replay(
1398 InboundLedger::Reason::GENERIC, finalHash_early, totalReplay);
1399 BEAST_EXPECT(net.client.waitAndCheckStatus(
1400 finalHash_early,
1401 totalReplay,
1404 deltaStatuses)); // deltaStatuses no change
1405 BEAST_EXPECT(net.client.waitForLedgers(finalHash_early, totalReplay));
1406 BEAST_EXPECT(net.client.countsAsExpected(3, 2, 2 * (totalReplay - 1)));
1407
1408 // partial overlap
1409 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1410 auto finalHash_moreEarly = l->header().parentHash;
1411 net.client.replayer.replay(
1412 InboundLedger::Reason::GENERIC, finalHash_moreEarly, totalReplay);
1413 BEAST_EXPECT(net.client.waitAndCheckStatus(
1414 finalHash_moreEarly,
1415 totalReplay,
1418 deltaStatuses)); // deltaStatuses no change
1419 BEAST_EXPECT(
1420 net.client.waitForLedgers(finalHash_moreEarly, totalReplay));
1421 BEAST_EXPECT(
1422 net.client.countsAsExpected(4, 3, 2 * (totalReplay - 1) + 2));
1423
1424 // cover
1425 net.client.replayer.replay(
1426 InboundLedger::Reason::GENERIC, finalHash, totalReplay * 3);
1427 deltaStatuses =
1428 std::vector<TaskStatus>(totalReplay * 3 - 1, TaskStatus::Completed);
1429 BEAST_EXPECT(net.client.waitAndCheckStatus(
1430 finalHash,
1431 totalReplay * 3,
1434 deltaStatuses)); // deltaStatuses changed
1435 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay * 3));
1436 BEAST_EXPECT(net.client.countsAsExpected(5, 3, totalReplay * 3 - 1));
1437
1438 // sweep
1439 net.client.replayer.sweep();
1440 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1441 }
1442
1443 void
1464};
1465
1467{
1468 void
1470 {
1471 testcase("SkipListAcquire timeout");
1472 int totalReplay = 3;
1473 NetworkOfTwo net(
1474 *this,
1475 {totalReplay + 1},
1479
1480 auto l = net.server.ledgerMaster.getClosedLedger();
1481 uint256 finalHash = l->header().hash;
1482 net.client.replayer.replay(
1483 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1484
1485 std::vector<TaskStatus> deltaStatuses;
1486 BEAST_EXPECT(net.client.waitAndCheckStatus(
1487 finalHash,
1488 totalReplay,
1491 deltaStatuses));
1492
1493 // sweep
1494 BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0));
1495 net.client.replayer.sweep();
1496 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1497 }
1498
1499 void
1501 {
1502 testcase("LedgerDeltaAcquire timeout");
1503 int totalReplay = 3;
1504 NetworkOfTwo net(
1505 *this,
1506 {totalReplay + 1},
1510
1511 auto l = net.server.ledgerMaster.getClosedLedger();
1512 uint256 finalHash = l->header().hash;
1513 net.client.ledgerMaster.storeLedger(l);
1514 net.client.replayer.replay(
1515 InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1516
1517 std::vector<TaskStatus> deltaStatuses(
1518 totalReplay - 1, TaskStatus::Failed);
1519 deltaStatuses.back() = TaskStatus::Completed; // in client ledgerMaster
1520 BEAST_EXPECT(net.client.waitAndCheckStatus(
1521 finalHash,
1522 totalReplay,
1525 deltaStatuses));
1526
1527 // sweep
1528 BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1));
1529 net.client.replayer.sweep();
1530 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1531 }
1532
1533 void
1534 run() override
1535 {
1538 }
1539};
1540
1542{
1543 void
1544 run() override
1545 {
1546 testcase("Acquire 1000 ledgers");
1547 int totalReplay = 250;
1548 int rounds = 4;
1549 NetworkOfTwo net(
1550 *this,
1551 {totalReplay * rounds + 1},
1555
1556 std::vector<uint256> finishHashes;
1557 auto l = net.server.ledgerMaster.getClosedLedger();
1558 for (int i = 0; i < rounds; ++i)
1559 {
1560 finishHashes.push_back(l->header().hash);
1561 for (int j = 0; j < totalReplay; ++j)
1562 {
1563 l = net.server.ledgerMaster.getLedgerByHash(
1564 l->header().parentHash);
1565 }
1566 }
1567 BEAST_EXPECT(finishHashes.size() == rounds);
1568
1569 for (int i = 0; i < rounds; ++i)
1570 {
1571 net.client.replayer.replay(
1572 InboundLedger::Reason::GENERIC, finishHashes[i], totalReplay);
1573 }
1574
1575 std::vector<TaskStatus> deltaStatuses(
1576 totalReplay - 1, TaskStatus::Completed);
1577 for (int i = 0; i < rounds; ++i)
1578 {
1579 BEAST_EXPECT(net.client.waitAndCheckStatus(
1580 finishHashes[i],
1581 totalReplay,
1584 deltaStatuses));
1585 }
1586
1587 BEAST_EXPECT(
1588 net.client.waitForLedgers(finishHashes[0], totalReplay * rounds));
1589 BEAST_EXPECT(net.client.countsAsExpected(
1590 rounds, rounds, rounds * (totalReplay - 1)));
1591
1592 // sweep
1593 net.client.replayer.sweep();
1594 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1595 }
1596};
1597
1598BEAST_DEFINE_TESTSUITE(LedgerReplay, app, xrpl);
1599BEAST_DEFINE_TESTSUITE_PRIO(LedgerReplayer, app, xrpl, 1);
1600BEAST_DEFINE_TESTSUITE(LedgerReplayerTimeout, app, xrpl);
1601BEAST_DEFINE_TESTSUITE_MANUAL(LedgerReplayerLong, app, xrpl);
1602
1603} // namespace test
1604} // namespace xrpl
T back(T... args)
Represents a JSON value.
Definition json_value.h:131
A version-independent IP address and port combination.
Definition IPEndpoint.h:19
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
virtual Config & config()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual Logs & logs()=0
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition Config.cpp:461
bool LEDGER_REPLAY
Definition Config.h:205
Manages the lifetime of inbound ledgers.
bool storeLedger(std::shared_ptr< Ledger const > ledger)
std::shared_ptr< Ledger const > getClosedLedger()
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
bool processProofPathResponse(std::shared_ptr< protocol::TMProofPathResponse > const &msg)
Process TMProofPathResponse.
protocol::TMProofPathResponse processProofPathRequest(std::shared_ptr< protocol::TMProofPathRequest > const &msg)
Process TMProofPathRequest and return TMProofPathResponse.
bool processReplayDeltaResponse(std::shared_ptr< protocol::TMReplayDeltaResponse > const &msg)
Process TMReplayDeltaResponse.
protocol::TMReplayDeltaResponse processReplayDeltaRequest(std::shared_ptr< protocol::TMReplayDeltaRequest > const &msg)
Process TMReplayDeltaRequest and return TMReplayDeltaResponse.
bool update(uint256 const &hash, std::uint32_t seq, std::vector< uint256 > const &sList)
fill all the fields that was not filled during construction
bool canMergeInto(TaskParameter const &existingTask) const
check if this task can be merged into an existing task
Manages the lifetime of ledger replay tasks.
hash_map< uint256, std::weak_ptr< SkipListAcquire > > skipLists_
std::vector< std::shared_ptr< LedgerReplayTask > > tasks_
hash_map< uint256, std::weak_ptr< LedgerDeltaAcquire > > deltas_
beast::severities::Severity threshold() const
Definition Log.cpp:147
Supports data retrieval by managing a set of peers.
Definition PeerSet.h:21
Represents a peer connection in the overlay.
std::uint32_t id_t
Uniquely identifies a peer.
A public key.
Definition PublicKey.h:43
A consumption charge.
Definition Charge.h:11
An immutable linear range of bytes.
Definition Slice.h:27
pointer data()
Definition base_uint.h:106
static constexpr std::size_t size()
Definition base_uint.h:507
Ledger replay client side.
TaskStatus taskStatus(std::shared_ptr< T > const &t)
std::vector< std::shared_ptr< LedgerReplayTask > > getTasks()
bool asExpected(uint256 const &hash, int totalReplay, TaskStatus taskExpect, TaskStatus skiplistExpect, std::vector< TaskStatus > const &deltaExpects)
LedgerReplayMsgHandler clientMsgHandler
bool haveLedgers(uint256 const &finishLedgerHash, int totalReplay)
void addLedger(std::shared_ptr< Ledger const > const &l)
std::shared_ptr< SkipListAcquire > findSkipListAcquire(uint256 const &hash)
bool countsAsExpected(std::size_t tasks, std::size_t skipLists, std::size_t deltas)
bool waitForLedgers(uint256 const &finishLedgerHash, int totalReplay)
LedgerReplayMsgHandler serverMsgHandler
LedgerReplayClient(beast::unit_test::suite &suite, LedgerServer &server, PeerSetBehavior behavior=PeerSetBehavior::Good, InboundLedgersBehavior inboundBhvr=InboundLedgersBehavior::Good, PeerFeature peerFeature=PeerFeature::LedgerReplayEnabled)
bool waitAndCheckStatus(uint256 const &hash, int totalReplay, TaskStatus taskExpect, TaskStatus skiplistExpect, std::vector< TaskStatus > const &deltaExpects)
bool asExpected(std::shared_ptr< LedgerReplayTask > const &task, TaskStatus taskExpect, TaskStatus skiplistExpect, std::vector< TaskStatus > const &deltaExpects)
std::shared_ptr< LedgerReplayTask > findTask(uint256 const &hash, int totalReplay)
bool checkStatus(uint256 const &hash, int totalReplay, TaskStatus taskExpect, TaskStatus skiplistExpect, std::vector< TaskStatus > const &deltaExpects)
std::shared_ptr< LedgerDeltaAcquire > findLedgerDeltaAcquire(uint256 const &hash)
Simulate a network InboundLedgers.
virtual size_t cacheSize() override
virtual void logFailure(uint256 const &h, std::uint32_t seq) override
MagicInboundLedgers(LedgerMaster &ledgerSource, LedgerMaster &ledgerSink, InboundLedgersBehavior bhvr)
virtual void gotFetchPack() override
virtual ~MagicInboundLedgers()=default
virtual void acquireAsync(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason reason) override
virtual void clearFailures() override
virtual bool gotLedgerData(LedgerHash const &ledgerHash, std::shared_ptr< Peer >, std::shared_ptr< protocol::TMLedgerData >) override
virtual std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason) override
virtual Json::Value getInfo() override
virtual std::size_t fetchRate() override
Returns the rate of historical ledger fetches per minute.
virtual std::shared_ptr< InboundLedger > find(LedgerHash const &hash) override
virtual void onLedgerFetched() override
Called when a complete ledger is obtained.
virtual bool isFailure(uint256 const &h) override
virtual void gotStaleData(std::shared_ptr< protocol::TMLedgerData > packet) override
LedgerReplayMsgHandler & remote
TestPeerSetBuilder(LedgerReplayMsgHandler &me, LedgerReplayMsgHandler &other, PeerSetBehavior bhvr, PeerFeature peerFeature)
std::unique_ptr< PeerSet > build() override
Simulate a network peer.
uint256 const & getClosedLedgerHash() const override
std::optional< std::size_t > publisherListSequence(PublicKey const &) const override
bool supportsFeature(ProtocolFeature f) const override
PublicKey const & getNodePublic() const override
beast::IP::Endpoint getRemoteAddress() const override
std::string const & fingerprint() const override
void ledgerRange(std::uint32_t &minSeq, std::uint32_t &maxSeq) const override
bool compressionEnabled() 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.
Json::Value json() override
bool hasLedger(uint256 const &hash, std::uint32_t seq) const override
bool txReduceRelayEnabled() const override
TestPeer(bool enableLedgerReplay)
id_t id() const override
bool hasTxSet(uint256 const &hash) const override
int getScore(bool) const override
bool isHighLatency() const override
bool cluster() const override
Returns true if this connection is a member of the cluster.
void addTxQueue(uint256 const &) override
Aggregate transaction's hash.
void removeTxQueue(uint256 const &) override
Remove hash from the transactions' hashes queue.
void send(std::shared_ptr< Message > const &m) override
void sendTxQueue() override
Send aggregated transactions' hashes.
bool hasRange(std::uint32_t uMin, std::uint32_t uMax) override
void setPublisherListSequence(PublicKey const &, std::size_t const) override
Immutable cryptographic account descriptor.
Definition Account.h:20
A transaction testing environment.
Definition Env.h:102
Application & app()
Definition Env.h:244
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:104
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:272
Env & apply(JsonValue &&jv, FN const &... fN)
Apply funclets and submit.
Definition Env.h:565
beast::Journal const journal
Definition Env.h:143
Set the fee on a JTx.
Definition fee.h:18
Set the regular signature on a JTx.
Definition sig.h:16
T count(T... args)
T emplace_back(T... args)
T find_if(T... args)
T insert(T... args)
T is_same_v
boost::asio::ip::address Address
Definition IPAddress.h:20
A namespace for easy access to logging severity values.
Definition Journal.h:11
Severity
Severity level / threshold of a Journal message.
Definition Journal.h:13
STL namespace.
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:178
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:11
static autofill_t const autofill
Definition tags.h:23
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:35
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
static uint256 ledgerHash(LedgerHeader const &info)
void logAll(LedgerServer &server, LedgerReplayClient &client, beast::severities::Severity level=Severity::kTrace)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
KeyType
Definition KeyType.h:9
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:142
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:14
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
base_uint< 256 > uint256
Definition base_uint.h:539
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:179
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
std::shared_ptr< Ledger > buildLedger(std::shared_ptr< Ledger const > const &parent, NetClock::time_point closeTime, bool const closeTimeCorrect, NetClock::duration closeResolution, Application &app, CanonicalTXSet &txns, std::set< TxID > &failedTxs, beast::Journal j)
Build a new ledger by applying consensus transactions.
@ tapNONE
Definition ApplyView.h:12
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.
@ ledgerMaster
ledger master data for signing
static constexpr char FEATURE_LEDGER_REPLAY[]
Definition Handshake.h:128
T push_back(T... args)
T size(T... args)
T sleep_for(T... args)
uint256 key
Definition Keylet.h:21
void run() override
Runs the suite.
void run() override
Runs the suite.
Test cases: LedgerReplayer_test: – process TMProofPathRequest and TMProofPathResponse – process TMRep...
void run() override
Runs the suite.
void testPeerSetBehavior(PeerSetBehavior peerSetBehavior, int totalReplay=4)
void testAllInboundLedgers(int totalReplay)
Utility class for (1) creating ledgers with txns and (2) providing the ledgers via the ledgerMaster.
std::vector< jtx::Account > accounts
LedgerServer(beast::unit_test::suite &suite, Parameter const &p)
void createLedgerHistory()
create ledger history
LedgerReplayMsgHandler msgHandler
void createAccounts(int newAccounts)
NetworkOfTwo(beast::unit_test::suite &suite, LedgerServer::Parameter const &param, PeerSetBehavior behavior=PeerSetBehavior::Good, InboundLedgersBehavior inboundBhvr=InboundLedgersBehavior::Good, PeerFeature peerFeature=PeerFeature::LedgerReplayEnabled)
Simulate a peerSet that supplies peers to ledger replay subtasks.
std::set< Peer::id_t > const & getPeerIds() const override
get the set of ids of previously added peers
LedgerReplayMsgHandler & local
std::shared_ptr< TestPeer > dummyPeer
TestPeerSet(LedgerReplayMsgHandler &me, LedgerReplayMsgHandler &other, PeerSetBehavior bhvr, bool enableLedgerReplay)
void sendRequest(::google::protobuf::Message const &msg, protocol::MessageType type, std::shared_ptr< Peer > const &peer) override
LedgerReplayMsgHandler & remote
void addPeers(std::size_t limit, std::function< bool(std::shared_ptr< Peer > const &)> hasItem, std::function< void(std::shared_ptr< Peer > const &)> onPeerAdded) override
Try add more peers.
Set the sequence number on a JTx.
Definition seq.h:15
T to_string(T... args)