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 = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
43
44 auto const replayed = buildLedger(LedgerReplay(lastClosedParent, lastClosed), tapNONE, env.app(), env.journal);
45
46 BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
47 }
48};
49
51 Good,
52 DropAll,
53};
54
61{
62public:
67 virtual ~MagicInboundLedgers() = default;
68
71 {
73 return {};
74 if (auto l = ledgerSource.getLedgerByHash(hash); l)
75 {
77 return l;
78 }
79
80 return {};
81 }
82
83 virtual void
85 {
86 }
87
89 find(LedgerHash const& hash) override
90 {
91 return {};
92 }
93
94 virtual bool
99
100 virtual void
104
105 virtual void
107 {
108 }
109
110 virtual bool
111 isFailure(uint256 const& h) override
112 {
113 return false;
114 }
115
116 virtual void
117 clearFailures() override
118 {
119 }
120
121 virtual Json::Value
122 getInfo() override
123 {
124 return {};
125 }
126
127 virtual std::size_t
128 fetchRate() override
129 {
130 return 0;
131 }
132
133 virtual void
135 {
136 }
137
138 virtual void
139 gotFetchPack() override
140 {
141 }
142 virtual void
143 sweep() override
144 {
145 }
146
147 virtual void
148 stop() override
149 {
150 }
151
152 virtual size_t
153 cacheSize() override
154 {
155 return 0;
156 }
157
161};
162
163enum class PeerFeature {
165 None,
166};
167
173class TestPeer : public Peer
174{
175public:
176 TestPeer(bool enableLedgerReplay)
178 {
179 }
180
181 void
183 {
184 }
186 getRemoteAddress() const override
187 {
188 return {};
189 }
190 void
191 charge(Resource::Charge const& fee, std::string const& context = {}) override
192 {
193 }
194 id_t
195 id() const override
196 {
197 return 1234;
198 }
199 bool
200 cluster() const override
201 {
202 return false;
203 }
204 bool
205 isHighLatency() const override
206 {
207 return false;
208 }
209 int
210 getScore(bool) const override
211 {
212 return 0;
213 }
214 PublicKey const&
215 getNodePublic() const override
216 {
217 return nodePublicKey_;
218 }
220 json() override
221 {
222 return {};
223 }
224 bool
226 {
228 return true;
229 return false;
230 }
232 publisherListSequence(PublicKey const&) const override
233 {
234 return {};
235 }
236 void
238 {
239 }
240 uint256 const&
241 getClosedLedgerHash() const override
242 {
243 static uint256 hash{};
244 return hash;
245 }
246 bool
247 hasLedger(uint256 const& hash, std::uint32_t seq) const override
248 {
249 return true;
250 }
251 void
252 ledgerRange(std::uint32_t& minSeq, std::uint32_t& maxSeq) const override
253 {
254 }
255 bool
256 hasTxSet(uint256 const& hash) const override
257 {
258 return false;
259 }
260 void
261 cycleStatus() override
262 {
263 }
264 bool
266 {
267 return false;
268 }
269 bool
270 compressionEnabled() const override
271 {
272 return false;
273 }
274 void
275 sendTxQueue() override
276 {
277 }
278 void
279 addTxQueue(uint256 const&) override
280 {
281 }
282 void
283 removeTxQueue(uint256 const&) override
284 {
285 }
286 bool
287 txReduceRelayEnabled() const override
288 {
289 return false;
290 }
291
292 std::string const&
293 fingerprint() const override
294 {
295 return fingerprint_;
296 }
297
301};
302
303enum class PeerSetBehavior {
304 Good,
305 Drop50,
306 DropAll,
309 Repeat,
310};
311
318struct TestPeerSet : public PeerSet
319{
323 PeerSetBehavior bhvr,
324 bool enableLedgerReplay)
325 : local(me), remote(other), dummyPeer(std::make_shared<TestPeer>(enableLedgerReplay)), behavior(bhvr)
326 {
327 }
328
329 void
331 std::size_t limit,
332 std::function<bool(std::shared_ptr<Peer> const&)> hasItem,
333 std::function<void(std::shared_ptr<Peer> const&)> onPeerAdded) override
334 {
335 hasItem(dummyPeer);
336 onPeerAdded(dummyPeer);
337 }
338
339 void
340 sendRequest(::google::protobuf::Message const& msg, protocol::MessageType type, std::shared_ptr<Peer> const& peer)
341 override
342 {
343 int dropRate = 0;
345 dropRate = 50;
347 dropRate = 100;
348
349 if ((rand() % 100 + 1) <= dropRate)
350 return;
351
352 switch (type)
353 {
354 case protocol::mtPROOF_PATH_REQ: {
356 return;
358 dynamic_cast<protocol::TMProofPathRequest const&>(msg));
363 break;
364 }
365 case protocol::mtREPLAY_DELTA_REQ: {
367 return;
369 dynamic_cast<protocol::TMReplayDeltaRequest const&>(msg));
370 auto reply =
375 break;
376 }
377 default:
378 return;
379 }
380 }
381
383 getPeerIds() const override
384 {
385 static std::set<Peer::id_t> emptyPeers;
386 return emptyPeers;
387 }
388
393};
394
422
428{
430 {
432 int initAccounts = 10;
433 int initAmount = 1'000'000;
435 int txAmount = 10;
436 };
437
439 : env(suite)
440 , app(env.app())
441 , ledgerMaster(env.app().getLedgerMaster())
442 , msgHandler(env.app(), env.app().getLedgerReplayer())
443 , param(p)
444 {
445 assert(param.initLedgers > 0);
449 }
450
454 void
455 createAccounts(int newAccounts)
456 {
457 auto fundedAccounts = accounts.size();
458 for (int i = 0; i < newAccounts; ++i)
459 {
460 accounts.emplace_back("alice_" + std::to_string(fundedAccounts + i));
462 }
463 env.close();
464 }
465
469 void
470 sendPayments(int newTxes)
471 {
472 int fundedAccounts = accounts.size();
473 assert(fundedAccounts >= newTxes);
475
476 // somewhat random but reproducible
477 int r = ledgerMaster.getClosedLedger()->seq() * 7;
478 int fromIdx = 0;
479 int toIdx = 0;
480 auto updateIdx = [&]() {
481 assert(fundedAccounts > senders.size());
482 fromIdx = (fromIdx + r) % fundedAccounts;
483 while (senders.count(fromIdx) != 0)
484 fromIdx = (fromIdx + 1) % fundedAccounts;
485 senders.insert(fromIdx);
486 toIdx = (toIdx + r * 2) % fundedAccounts;
487 if (toIdx == fromIdx)
488 toIdx = (toIdx + 1) % fundedAccounts;
489 };
490
491 for (int i = 0; i < newTxes; ++i)
492 {
493 updateIdx();
494 env(pay(accounts[fromIdx],
495 accounts[toIdx],
500 }
501 env.close();
502 }
503
507 void
509 {
510 for (int i = 0; i < param.initLedgers - 1; ++i)
511 {
513 }
514 }
515
522};
523
524enum class TaskStatus {
525 Failed,
526 Completed,
527 NotDone,
528 NotExist,
529};
530
539{
540public:
543 LedgerServer& server,
547 : env(suite, jtx::envconfig(), nullptr, beast::severities::kDisabled)
548 , app(env.app())
549 , ledgerMaster(env.app().getLedgerMaster())
550 , inboundLedgers(server.app.getLedgerMaster(), ledgerMaster, inboundBhvr)
551 , serverMsgHandler(server.app, server.app.getLedgerReplayer())
553 , replayer(
554 env.app(),
556 std::make_unique<TestPeerSetBuilder>(clientMsgHandler, serverMsgHandler, behavior, peerFeature))
557 {
558 }
559
560 void
565
566 bool
567 haveLedgers(uint256 const& finishLedgerHash, int totalReplay)
568 {
569 uint256 hash = finishLedgerHash;
570 int i = 0;
571 for (; i < totalReplay; ++i)
572 {
573 auto const l = ledgerMaster.getLedgerByHash(hash);
574 if (!l)
575 return false;
576 hash = l->header().parentHash;
577 }
578 return true;
579 }
580
581 bool
582 waitForLedgers(uint256 const& finishLedgerHash, int totalReplay)
583 {
584 int totalRound = 100;
585 for (int i = 0; i < totalRound; ++i)
586 {
587 if (haveLedgers(finishLedgerHash, totalReplay))
588 return true;
589 if (i < totalRound - 1)
591 }
592 return false;
593 }
594
595 bool
597 {
598 int totalRound = 100;
599 for (int i = 0; i < totalRound; ++i)
600 {
601 bool allDone = true;
602 {
604 for (auto const& t : replayer.tasks_)
605 {
606 if (!t->finished())
607 {
608 allDone = false;
609 break;
610 }
611 }
612 }
613 if (allDone)
614 return true;
615 if (i < totalRound - 1)
617 }
618 return false;
619 }
620
623 {
625 return replayer.tasks_;
626 }
627
629 findTask(uint256 const& hash, int totalReplay)
630 {
632 auto i = std::find_if(replayer.tasks_.begin(), replayer.tasks_.end(), [&](auto const& t) {
633 return t->parameter_.finishHash_ == hash && t->parameter_.totalLedgers_ == totalReplay;
634 });
635 if (i == replayer.tasks_.end())
636 return {};
637 return *i;
638 }
639
642 {
644 return replayer.deltas_.size();
645 }
646
649 {
651 return replayer.skipLists_.size();
652 }
653
654 bool
656 {
658 return replayer.tasks_.size() == tasks && replayer.skipLists_.size() == skipLists &&
659 replayer.deltas_.size() == deltas;
660 }
661
664 {
666 auto i = replayer.skipLists_.find(hash);
667 if (i == replayer.skipLists_.end())
668 return {};
669 return i->second.lock();
670 }
671
674 {
676 auto i = replayer.deltas_.find(hash);
677 if (i == replayer.deltas_.end())
678 return {};
679 return i->second.lock();
680 }
681
682 template <typename T>
685 {
686 if (t->failed_)
687 return TaskStatus::Failed;
688 if (t->complete_)
690 return TaskStatus::NotDone;
691 }
692
693 bool
696 TaskStatus taskExpect,
697 TaskStatus skiplistExpect,
698 std::vector<TaskStatus> const& deltaExpects)
699 {
700 if (taskStatus(task) == taskExpect)
701 {
702 if (taskStatus(task->skipListAcquirer_) == skiplistExpect)
703 {
704 if (task->deltas_.size() == deltaExpects.size())
705 {
706 for (int i = 0; i < deltaExpects.size(); ++i)
707 {
708 if (taskStatus(task->deltas_[i]) != deltaExpects[i])
709 return false;
710 }
711 return true;
712 }
713 }
714 }
715 return false;
716 }
717
718 bool
720 uint256 const& hash,
721 int totalReplay,
722 TaskStatus taskExpect,
723 TaskStatus skiplistExpect,
724 std::vector<TaskStatus> const& deltaExpects)
725 {
726 auto t = findTask(hash, totalReplay);
727 if (!t)
728 {
729 if (taskExpect == TaskStatus::NotExist)
730 return true;
731 return false;
732 }
733
734 return asExpected(t, taskExpect, skiplistExpect, deltaExpects);
735 }
736
737 bool
739 uint256 const& hash,
740 int totalReplay,
741 TaskStatus taskExpect,
742 TaskStatus skiplistExpect,
743 std::vector<TaskStatus> const& deltaExpects)
744 {
745 auto t = findTask(hash, totalReplay);
746 if (!t)
747 {
748 if (taskExpect == TaskStatus::NotExist)
749 return true;
750 return false;
751 }
752
753 return asExpected(t, taskExpect, skiplistExpect, deltaExpects);
754 }
755
756 bool
758 uint256 const& hash,
759 int totalReplay,
760 TaskStatus taskExpect,
761 TaskStatus skiplistExpect,
762 std::vector<TaskStatus> const& deltaExpects)
763 {
764 if (!waitForDone())
765 return false;
766
767 return checkStatus(hash, totalReplay, taskExpect, skiplistExpect, deltaExpects);
768 }
769
777};
778
779using namespace beast::severities;
780void
781logAll(LedgerServer& server, LedgerReplayClient& client, beast::severities::Severity level = Severity::kTrace)
782{
783 server.app.logs().threshold(level);
784 client.app.logs().threshold(level);
785}
786// logAll(net.server, net.client);
787
788/*
789 * Create a LedgerServer and a LedgerReplayClient
790 */
792{
795 LedgerServer::Parameter const& param,
799 : server(suite, param), client(suite, server, behavior, inboundBhvr, peerFeature)
800 {
801 // logAll(server, client);
802 }
805};
806
833{
834 void
836 {
837 testcase("ProofPath");
838 LedgerServer server(*this, {1});
839 auto const l = server.ledgerMaster.getClosedLedger();
840
841 {
842 // request, missing key
844 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
845 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
846 auto reply =
847 std::make_shared<protocol::TMProofPathResponse>(server.msgHandler.processProofPathRequest(request));
848 BEAST_EXPECT(reply->has_error());
849 BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply));
850 }
851 {
852 // request, wrong hash
854 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
855 request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
856 uint256 hash(1234567);
857 request->set_ledgerhash(hash.data(), hash.size());
858 auto reply =
859 std::make_shared<protocol::TMProofPathResponse>(server.msgHandler.processProofPathRequest(request));
860 BEAST_EXPECT(reply->has_error());
861 }
862
863 {
864 // good request
866 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
867 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
868 request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
869 // generate response
870 auto reply =
871 std::make_shared<protocol::TMProofPathResponse>(server.msgHandler.processProofPathRequest(request));
872 BEAST_EXPECT(!reply->has_error());
873 BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply));
874
875 {
876 // bad reply
877 // bad header
878 std::string r(reply->ledgerheader());
879 r.back()--;
880 reply->set_ledgerheader(r);
881 BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply));
882 r.back()++;
883 reply->set_ledgerheader(r);
884 BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply));
885 // bad proof path
886 reply->mutable_path()->RemoveLast();
887 BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply));
888 }
889 }
890 }
891
892 void
894 {
895 testcase("ReplayDelta");
896 LedgerServer server(*this, {1});
897 auto const l = server.ledgerMaster.getClosedLedger();
898
899 {
900 // request, missing hash
902 auto reply =
903 std::make_shared<protocol::TMReplayDeltaResponse>(server.msgHandler.processReplayDeltaRequest(request));
904 BEAST_EXPECT(reply->has_error());
905 BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
906 // request, wrong hash
907 uint256 hash(1234567);
908 request->set_ledgerhash(hash.data(), hash.size());
909 reply =
910 std::make_shared<protocol::TMReplayDeltaResponse>(server.msgHandler.processReplayDeltaRequest(request));
911 BEAST_EXPECT(reply->has_error());
912 BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
913 }
914
915 {
916 // good request
918 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
919 auto reply =
920 std::make_shared<protocol::TMReplayDeltaResponse>(server.msgHandler.processReplayDeltaRequest(request));
921 BEAST_EXPECT(!reply->has_error());
922 BEAST_EXPECT(server.msgHandler.processReplayDeltaResponse(reply));
923
924 {
925 // bad reply
926 // bad header
927 std::string r(reply->ledgerheader());
928 r.back()--;
929 reply->set_ledgerheader(r);
930 BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
931 r.back()++;
932 reply->set_ledgerheader(r);
933 BEAST_EXPECT(server.msgHandler.processReplayDeltaResponse(reply));
934 // bad txns
935 reply->mutable_transaction()->RemoveLast();
936 BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
937 }
938 }
939 }
940
941 void
943 {
944 testcase("TaskParameter");
945
946 auto makeSkipList = [](int count) -> std::vector<uint256> const {
948 for (int i = 0; i < count; ++i)
949 sList.emplace_back(i);
950 return sList;
951 };
952
954 BEAST_EXPECT(!tp10.update(uint256(777), 5, makeSkipList(10)));
955 BEAST_EXPECT(!tp10.update(uint256(10), 5, makeSkipList(8)));
956 BEAST_EXPECT(tp10.update(uint256(10), 10, makeSkipList(10)));
957
958 // can merge to self
959 BEAST_EXPECT(tp10.canMergeInto(tp10));
960
961 // smaller task
963
964 BEAST_EXPECT(tp9.canMergeInto(tp10));
965 BEAST_EXPECT(!tp10.canMergeInto(tp9));
966
967 tp9.totalLedgers_++;
968 BEAST_EXPECT(!tp9.canMergeInto(tp10));
969 tp9.totalLedgers_--;
970 BEAST_EXPECT(tp9.canMergeInto(tp10));
971
973 BEAST_EXPECT(!tp9.canMergeInto(tp10));
975 BEAST_EXPECT(tp9.canMergeInto(tp10));
976
977 tp9.finishHash_ = uint256(1234);
978 BEAST_EXPECT(!tp9.canMergeInto(tp10));
979 tp9.finishHash_ = uint256(9);
980 BEAST_EXPECT(tp9.canMergeInto(tp10));
981
982 // larger task
984 BEAST_EXPECT(tp20.update(uint256(20), 20, makeSkipList(20)));
985 BEAST_EXPECT(tp10.canMergeInto(tp20));
986 BEAST_EXPECT(tp9.canMergeInto(tp20));
987 BEAST_EXPECT(!tp20.canMergeInto(tp10));
988 BEAST_EXPECT(!tp20.canMergeInto(tp9));
989 }
990
991 void
993 {
994 testcase("config test");
995 {
996 Config c;
997 BEAST_EXPECT(c.LEDGER_REPLAY == false);
998 }
999
1000 {
1001 Config c;
1002 std::string toLoad(R"rippleConfig(
1003[ledger_replay]
10041
1005)rippleConfig");
1006 c.loadFromString(toLoad);
1007 BEAST_EXPECT(c.LEDGER_REPLAY == true);
1008 }
1009
1010 {
1011 Config c;
1012 std::string toLoad = (R"rippleConfig(
1013[ledger_replay]
10140
1015)rippleConfig");
1016 c.loadFromString(toLoad);
1017 BEAST_EXPECT(c.LEDGER_REPLAY == false);
1018 }
1019 }
1020
1021 void
1023 {
1024 testcase("handshake test");
1025 auto handshake = [&](bool client, bool server, bool expecting) -> bool {
1026 auto request = xrpl::makeRequest(true, false, client, false, false);
1027 http_request_type http_request;
1028 http_request.version(request.version());
1029 http_request.base() = request.base();
1030 bool serverResult = peerFeatureEnabled(http_request, FEATURE_LEDGER_REPLAY, server);
1031 if (serverResult != expecting)
1032 return false;
1033
1034 beast::IP::Address addr = boost::asio::ip::make_address("172.1.1.100");
1035 jtx::Env serverEnv(*this);
1036 serverEnv.app().config().LEDGER_REPLAY = server;
1037 auto http_resp = xrpl::makeResponse(true, http_request, addr, addr, uint256{1}, 1, {1, 0}, serverEnv.app());
1038 auto const clientResult = peerFeatureEnabled(http_resp, FEATURE_LEDGER_REPLAY, client);
1039 if (clientResult != expecting)
1040 return false;
1041
1042 return true;
1043 };
1044
1045 BEAST_EXPECT(handshake(false, false, false));
1046 BEAST_EXPECT(handshake(false, true, false));
1047 BEAST_EXPECT(handshake(true, false, false));
1048 BEAST_EXPECT(handshake(true, true, true));
1049 }
1050
1051 void
1052 testAllLocal(int totalReplay)
1053 {
1054 testcase("local node has all the ledgers");
1055 auto psBhvr = PeerSetBehavior::DropAll;
1056 auto ilBhvr = InboundLedgersBehavior::DropAll;
1057 auto peerFeature = PeerFeature::None;
1058
1059 NetworkOfTwo net(*this, {totalReplay + 1}, psBhvr, ilBhvr, peerFeature);
1060
1061 auto l = net.server.ledgerMaster.getClosedLedger();
1062 uint256 finalHash = l->header().hash;
1063 for (int i = 0; i < totalReplay; ++i)
1064 {
1065 BEAST_EXPECT(l);
1066 if (l)
1067 {
1068 net.client.ledgerMaster.storeLedger(l);
1069 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1070 }
1071 else
1072 break;
1073 }
1074
1075 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1076
1077 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1078 BEAST_EXPECT(net.client.waitAndCheckStatus(
1079 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1080
1081 // sweep
1082 net.client.replayer.sweep();
1083 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1084 }
1085
1086 void
1087 testAllInboundLedgers(int totalReplay)
1088 {
1089 testcase("all the ledgers from InboundLedgers");
1090 NetworkOfTwo net(
1092
1093 auto l = net.server.ledgerMaster.getClosedLedger();
1094 uint256 finalHash = l->header().hash;
1095 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1096
1097 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1098 BEAST_EXPECT(net.client.waitAndCheckStatus(
1099 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1100
1101 // sweep
1102 net.client.replayer.sweep();
1103 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1104 }
1105
1106 void
1107 testPeerSetBehavior(PeerSetBehavior peerSetBehavior, int totalReplay = 4)
1108 {
1109 switch (peerSetBehavior)
1110 {
1112 testcase("good network");
1113 break;
1115 testcase("network drops 50% messages");
1116 break;
1118 testcase("network repeats all messages");
1119 break;
1120 default:
1121 return;
1122 }
1123
1124 NetworkOfTwo net(
1125 *this,
1126 {totalReplay + 1},
1127 peerSetBehavior,
1130
1131 // feed client with start ledger since InboundLedgers drops all
1132 auto l = net.server.ledgerMaster.getClosedLedger();
1133 uint256 finalHash = l->header().hash;
1134 for (int i = 0; i < totalReplay - 1; ++i)
1135 {
1136 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1137 }
1138 net.client.ledgerMaster.storeLedger(l);
1139
1140 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1141
1142 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1143 BEAST_EXPECT(net.client.waitAndCheckStatus(
1144 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1145 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay));
1146
1147 // sweep
1148 net.client.replayer.sweep();
1149 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1150 }
1151
1152 void
1154 {
1155 testcase("stop before timeout");
1156 int totalReplay = 3;
1157 NetworkOfTwo net(
1158 *this,
1159 {totalReplay + 1},
1163
1164 auto l = net.server.ledgerMaster.getClosedLedger();
1165 uint256 finalHash = l->header().hash;
1166 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1167
1168 std::vector<TaskStatus> deltaStatuses;
1169 BEAST_EXPECT(
1170 net.client.checkStatus(finalHash, totalReplay, TaskStatus::NotDone, TaskStatus::NotDone, deltaStatuses));
1171
1172 BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0));
1173 net.client.replayer.stop();
1174 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1175 }
1176
1177 void
1179 {
1180 testcase("SkipListAcquire bad reply");
1181 int totalReplay = 3;
1182 NetworkOfTwo net(
1183 *this,
1184 {totalReplay + 1 + 1},
1188
1189 auto l = net.server.ledgerMaster.getClosedLedger();
1190 uint256 finalHash = l->header().hash;
1191 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1192
1193 auto skipList = net.client.findSkipListAcquire(finalHash);
1194
1195 std::uint8_t payload[55] = {0x6A, 0x09, 0xE6, 0x67, 0xF3, 0xBC, 0xC9, 0x08, 0xB2};
1196 auto item = make_shamapitem(uint256(12345), Slice(payload, sizeof(payload)));
1197 skipList->processData(l->seq(), item);
1198
1199 std::vector<TaskStatus> deltaStatuses;
1200 BEAST_EXPECT(net.client.waitAndCheckStatus(
1201 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1202
1203 // add another task
1204 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1);
1205 BEAST_EXPECT(net.client.waitAndCheckStatus(
1206 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1207 BEAST_EXPECT(net.client.countsAsExpected(2, 1, 0));
1208 }
1209
1210 void
1212 {
1213 testcase("LedgerDeltaAcquire bad reply");
1214 int totalReplay = 3;
1215 NetworkOfTwo net(
1216 *this,
1217 {totalReplay + 1},
1221
1222 auto l = net.server.ledgerMaster.getClosedLedger();
1223 uint256 finalHash = l->header().hash;
1224 net.client.ledgerMaster.storeLedger(l);
1225 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1226
1227 auto delta = net.client.findLedgerDeltaAcquire(l->header().parentHash);
1228 delta->processData(
1229 l->header(), // wrong ledger info
1231 BEAST_EXPECT(net.client.taskStatus(delta) == TaskStatus::Failed);
1232 BEAST_EXPECT(net.client.taskStatus(net.client.findTask(finalHash, totalReplay)) == TaskStatus::Failed);
1233
1234 // add another task
1235 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1);
1236 BEAST_EXPECT(net.client.taskStatus(net.client.findTask(finalHash, totalReplay + 1)) == TaskStatus::Failed);
1237 }
1238
1239 void
1241 {
1242 testcase("Overlap tasks");
1243 int totalReplay = 5;
1244 NetworkOfTwo net(
1245 *this,
1246 {totalReplay * 3 + 1},
1250 auto l = net.server.ledgerMaster.getClosedLedger();
1251 uint256 finalHash = l->header().hash;
1252 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1253 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1254 BEAST_EXPECT(net.client.waitAndCheckStatus(
1255 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1256 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay));
1257
1258 // same range, same reason
1259 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1260 BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1));
1261 // same range, different reason
1262 net.client.replayer.replay(InboundLedger::Reason::CONSENSUS, finalHash, totalReplay);
1263 BEAST_EXPECT(net.client.countsAsExpected(2, 1, totalReplay - 1));
1264
1265 // no overlap
1266 for (int i = 0; i < totalReplay + 2; ++i)
1267 {
1268 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1269 }
1270 auto finalHash_early = l->header().hash;
1271 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash_early, totalReplay);
1272 BEAST_EXPECT(net.client.waitAndCheckStatus(
1273 finalHash_early,
1274 totalReplay,
1277 deltaStatuses)); // deltaStatuses no change
1278 BEAST_EXPECT(net.client.waitForLedgers(finalHash_early, totalReplay));
1279 BEAST_EXPECT(net.client.countsAsExpected(3, 2, 2 * (totalReplay - 1)));
1280
1281 // partial overlap
1282 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1283 auto finalHash_moreEarly = l->header().parentHash;
1284 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash_moreEarly, totalReplay);
1285 BEAST_EXPECT(net.client.waitAndCheckStatus(
1286 finalHash_moreEarly,
1287 totalReplay,
1290 deltaStatuses)); // deltaStatuses no change
1291 BEAST_EXPECT(net.client.waitForLedgers(finalHash_moreEarly, totalReplay));
1292 BEAST_EXPECT(net.client.countsAsExpected(4, 3, 2 * (totalReplay - 1) + 2));
1293
1294 // cover
1295 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay * 3);
1296 deltaStatuses = std::vector<TaskStatus>(totalReplay * 3 - 1, TaskStatus::Completed);
1297 BEAST_EXPECT(net.client.waitAndCheckStatus(
1298 finalHash,
1299 totalReplay * 3,
1302 deltaStatuses)); // deltaStatuses changed
1303 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay * 3));
1304 BEAST_EXPECT(net.client.countsAsExpected(5, 3, totalReplay * 3 - 1));
1305
1306 // sweep
1307 net.client.replayer.sweep();
1308 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1309 }
1310
1311 void
1332};
1333
1335{
1336 void
1338 {
1339 testcase("SkipListAcquire timeout");
1340 int totalReplay = 3;
1341 NetworkOfTwo net(
1342 *this,
1343 {totalReplay + 1},
1347
1348 auto l = net.server.ledgerMaster.getClosedLedger();
1349 uint256 finalHash = l->header().hash;
1350 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1351
1352 std::vector<TaskStatus> deltaStatuses;
1353 BEAST_EXPECT(net.client.waitAndCheckStatus(
1354 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1355
1356 // sweep
1357 BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0));
1358 net.client.replayer.sweep();
1359 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1360 }
1361
1362 void
1364 {
1365 testcase("LedgerDeltaAcquire timeout");
1366 int totalReplay = 3;
1367 NetworkOfTwo net(
1368 *this,
1369 {totalReplay + 1},
1373
1374 auto l = net.server.ledgerMaster.getClosedLedger();
1375 uint256 finalHash = l->header().hash;
1376 net.client.ledgerMaster.storeLedger(l);
1377 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1378
1379 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Failed);
1380 deltaStatuses.back() = TaskStatus::Completed; // in client ledgerMaster
1381 BEAST_EXPECT(net.client.waitAndCheckStatus(
1382 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Completed, deltaStatuses));
1383
1384 // sweep
1385 BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1));
1386 net.client.replayer.sweep();
1387 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1388 }
1389
1390 void
1391 run() override
1392 {
1395 }
1396};
1397
1399{
1400 void
1401 run() override
1402 {
1403 testcase("Acquire 1000 ledgers");
1404 int totalReplay = 250;
1405 int rounds = 4;
1406 NetworkOfTwo net(
1407 *this,
1408 {totalReplay * rounds + 1},
1412
1413 std::vector<uint256> finishHashes;
1414 auto l = net.server.ledgerMaster.getClosedLedger();
1415 for (int i = 0; i < rounds; ++i)
1416 {
1417 finishHashes.push_back(l->header().hash);
1418 for (int j = 0; j < totalReplay; ++j)
1419 {
1420 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1421 }
1422 }
1423 BEAST_EXPECT(finishHashes.size() == rounds);
1424
1425 for (int i = 0; i < rounds; ++i)
1426 {
1427 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finishHashes[i], totalReplay);
1428 }
1429
1430 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1431 for (int i = 0; i < rounds; ++i)
1432 {
1433 BEAST_EXPECT(net.client.waitAndCheckStatus(
1434 finishHashes[i], totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1435 }
1436
1437 BEAST_EXPECT(net.client.waitForLedgers(finishHashes[0], totalReplay * rounds));
1438 BEAST_EXPECT(net.client.countsAsExpected(rounds, rounds, rounds * (totalReplay - 1)));
1439
1440 // sweep
1441 net.client.replayer.sweep();
1442 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1443 }
1444};
1445
1446BEAST_DEFINE_TESTSUITE(LedgerReplay, app, xrpl);
1447BEAST_DEFINE_TESTSUITE_PRIO(LedgerReplayer, app, xrpl, 1);
1448BEAST_DEFINE_TESTSUITE(LedgerReplayerTimeout, app, xrpl);
1449BEAST_DEFINE_TESTSUITE_MANUAL(LedgerReplayerLong, app, xrpl);
1450
1451} // namespace test
1452} // namespace xrpl
T back(T... args)
Represents a JSON value.
Definition json_value.h:130
A version-independent IP address and port combination.
Definition IPEndpoint.h:18
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:147
virtual Config & config()=0
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition Config.cpp:440
bool LEDGER_REPLAY
Definition Config.h:204
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:140
Supports data retrieval by managing a set of peers.
Definition PeerSet.h:20
Represents a peer connection in the overlay.
std::uint32_t id_t
Uniquely identifies a peer.
A public key.
Definition PublicKey.h:42
A consumption charge.
Definition Charge.h:10
virtual Logs & logs()=0
virtual LedgerMaster & getLedgerMaster()=0
An immutable linear range of bytes.
Definition Slice.h:26
pointer data()
Definition base_uint.h:101
static constexpr std::size_t size()
Definition base_uint.h:494
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:19
A transaction testing environment.
Definition Env.h:119
Application & app()
Definition Env.h:251
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:98
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:261
beast::Journal const journal
Definition Env.h:160
Set the fee on a JTx.
Definition fee.h:17
Set the regular signature on a JTx.
Definition sig.h:15
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:19
A namespace for easy access to logging severity values.
Definition Journal.h:10
Severity
Severity level / threshold of a Journal message.
Definition Journal.h:12
STL namespace.
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:172
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:90
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:22
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:34
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:5
KeyType
Definition KeyType.h:8
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:137
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:12
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:526
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:168
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:11
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:124
T push_back(T... args)
T size(T... args)
T sleep_for(T... args)
uint256 key
Definition Keylet.h:20
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:14
T to_string(T... args)