xrpld
Loading...
Searching...
No Matches
LedgerReplay_test.cpp
1#include <test/jtx/Account.h>
2#include <test/jtx/Env.h>
3#include <test/jtx/PeerStub.h>
4#include <test/jtx/amount.h>
5#include <test/jtx/batch.h>
6#include <test/jtx/envconfig.h>
7#include <test/jtx/fee.h>
8#include <test/jtx/pay.h>
9#include <test/jtx/seq.h>
10#include <test/jtx/sig.h>
11#include <test/jtx/tags.h>
12#include <test/jtx/ter.h>
13
14#include <xrpld/app/ledger/BuildLedger.h>
15#include <xrpld/app/ledger/InboundLedger.h>
16#include <xrpld/app/ledger/InboundLedgers.h>
17#include <xrpld/app/ledger/LedgerMaster.h>
18#include <xrpld/app/ledger/LedgerReplay.h>
19#include <xrpld/app/ledger/LedgerReplayTask.h>
20#include <xrpld/app/ledger/LedgerReplayer.h>
21#include <xrpld/app/ledger/detail/LedgerDeltaAcquire.h>
22#include <xrpld/app/ledger/detail/LedgerReplayMsgHandler.h>
23#include <xrpld/app/ledger/detail/SkipListAcquire.h>
24#include <xrpld/core/Config.h>
25#include <xrpld/overlay/Peer.h>
26#include <xrpld/overlay/PeerSet.h>
27#include <xrpld/overlay/detail/Handshake.h>
28
29#include <xrpl/basics/Slice.h>
30#include <xrpl/basics/base_uint.h>
31#include <xrpl/beast/net/IPAddress.h>
32#include <xrpl/beast/unit_test/suite.h>
33#include <xrpl/beast/utility/Journal.h>
34#include <xrpl/json/json_value.h>
35#include <xrpl/ledger/ApplyView.h>
36#include <xrpl/protocol/Indexes.h>
37#include <xrpl/protocol/RippleLedgerHash.h>
38#include <xrpl/protocol/TER.h>
39#include <xrpl/protocol/TxFlags.h>
40#include <xrpl/server/Handoff.h>
41#include <xrpl/shamap/SHAMapItem.h>
42
43#include <boost/asio/ip/address.hpp>
44
45#include <google/protobuf/message.h>
46
47#include <xrpl.pb.h>
48
49#include <algorithm>
50#include <atomic>
51#include <cassert>
52#include <chrono>
53#include <cstddef>
54#include <cstdint>
55#include <cstdlib>
56#include <exception>
57#include <format>
58#include <functional>
59#include <map>
60#include <memory>
61#include <mutex>
62#include <optional>
63#include <set>
64#include <string>
65#include <thread>
66#include <unordered_set>
67#include <vector>
68
69namespace xrpl::test {
70
72{
73 void
75 {
76 testcase("Replay ledger");
77
78 using namespace jtx;
79
80 // Build a ledger normally
81 auto const alice = Account("alice");
82 auto const bob = Account("bob");
83
84 Env env(*this);
85 env.fund(XRP(100000), alice, bob);
86 env.close();
87
88 LedgerMaster& ledgerMaster = env.app().getLedgerMaster();
89 auto const lastClosed = ledgerMaster.getClosedLedger();
90 auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
91
92 auto const replayed = buildLedger(
93 LedgerReplay(lastClosedParent, lastClosed), TapNone, env.app(), env.journal);
94
95 BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
96 }
97
98 void
100 {
101 testcase("Replay ledger with batch transactions");
102
103 using namespace jtx;
104
105 Env env(*this, testableAmendments());
106
107 auto const alice = Account("alice");
108 auto const bob = Account("bob");
109 env.fund(XRP(100000), alice, bob);
110 env.close();
111
112 auto const seq = env.seq(alice);
113 auto const batchFee = batch::calcBatchFee(env, 0, 2);
114 env(batch::outer(alice, seq, batchFee, tfAllOrNothing),
115 batch::Inner(pay(alice, bob, XRP(1)), seq + 1),
116 batch::Inner(pay(alice, bob, XRP(2)), seq + 2),
117 Ter(tesSUCCESS));
118 env.close();
119
120 LedgerMaster& ledgerMaster = env.app().getLedgerMaster();
121 auto const lastClosed = ledgerMaster.getClosedLedger();
122 auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
123
124 auto const replayed = buildLedger(
125 LedgerReplay(lastClosedParent, lastClosed), TapNone, env.app(), env.journal);
126
127 BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
128 }
129
130 void
131 run() override
132 {
135 }
136};
137
142
149{
150public:
158 ~MagicInboundLedgers() override = default;
159
162 {
164 return {};
165 if (auto l = ledgerSource.getLedgerByHash(hash); l)
166 {
167 ledgerSink.storeLedger(l);
168 return l;
169 }
170
171 return {};
172 }
173
174 void
175 acquireAsync(UInt256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override
176 {
177 }
178
180 find(LedgerHash const& hash) override
181 {
182 return {};
183 }
184
185 bool
187 LedgerHash const& ledgerHash,
190 {
191 return false;
192 }
193
194 void
198
199 void
200 logFailure(UInt256 const& h, std::uint32_t seq) override
201 {
202 }
203
204 bool
205 isFailure(UInt256 const& h) override
206 {
207 return false;
208 }
209
210 void
211 clearFailures() override
212 {
213 }
214
216 getInfo() override
217 {
218 return {};
219 }
220
222 fetchRate() override
223 {
224 return 0;
225 }
226
227 void
229 {
230 }
231
232 void
233 gotFetchPack() override
234 {
235 }
236 void
237 sweep() override
238 {
239 }
240
241 void
242 stop() override
243 {
244 }
245
246 size_t
247 cacheSize() override
248 {
249 return 0;
250 }
251
255};
256
261
269class TestPeer : public PeerStub
270{
271public:
272 // Arbitrary but fixed: the replay code only compares ids.
273 explicit TestPeer(bool enableLedgerReplay)
274 : PeerStub(1234), ledgerReplayEnabled_(enableLedgerReplay)
275 {
276 }
277
278 [[nodiscard]] bool
283
284 // The replay code only asks peers that already have the ledger.
285 [[nodiscard]] bool
286 hasLedger(UInt256 const&, std::uint32_t) const override
287 {
288 return true;
289 }
290
291private:
293};
294
303
310struct TestPeerSet : public PeerSet
311{
315 PeerSetBehavior bhvr,
316 bool enableLedgerReplay)
317 : local(me)
318 , remote(other)
319 , dummyPeer(std::make_shared<TestPeer>(enableLedgerReplay))
320 , behavior(bhvr)
321 {
322 }
323
324 void
326 std::size_t limit,
327 std::function<bool(std::shared_ptr<Peer> const&)> hasItem,
328 std::function<void(std::shared_ptr<Peer> const&)> onPeerAdded) override
329 {
330 hasItem(dummyPeer);
331 onPeerAdded(dummyPeer);
332 }
333
334 void
336 ::google::protobuf::Message const& msg,
337 protocol::MessageType type,
338 std::shared_ptr<Peer> const& peer) override
339 {
341 return;
342
343 // Drop every other message deterministically. Alternating drops
344 // still exercise the timeout/retry path while guaranteeing every
345 // subtask eventually gets a reply.
347 return;
348
349 switch (type)
350 {
351 case protocol::mtPROOF_PATH_REQ: {
353 return;
355 dynamic_cast<protocol::TMProofPathRequest const&>(msg));
357 remote.processProofPathRequest(request));
358 local.processProofPathResponse(reply);
360 local.processProofPathResponse(reply);
361 break;
362 }
363 case protocol::mtREPLAY_DELTA_REQ: {
365 return;
367 dynamic_cast<protocol::TMReplayDeltaRequest const&>(msg));
369 remote.processReplayDeltaRequest(request));
370 local.processReplayDeltaResponse(reply);
372 local.processReplayDeltaResponse(reply);
373 break;
374 }
375 default:
376 return;
377 }
378 }
379
380 [[nodiscard]] std::set<Peer::ID> const&
381 getPeerIds() const override
382 {
383 static std::set<Peer::ID> const kEmptyPeers;
384 return kEmptyPeers;
385 }
386
392};
393
424
430{
432 {
434 int initAccounts = 10;
435 int initAmount = 1'000'000;
437 int txAmount = 10;
438 };
439
441 : env(suite)
442 , app(env.app())
443 , ledgerMaster(env.app().getLedgerMaster())
444 , msgHandler(env.app(), env.app().getLedgerReplayer())
445 , param(p)
446 {
447 assert(param.initLedgers > 0);
448 createAccounts(param.initAccounts);
450 app.getLogs().threshold(beast::Severity::Warning);
451 }
452
456 void
457 createAccounts(int newAccounts)
458 {
459 auto fundedAccounts = accounts.size();
460 for (int i = 0; i < newAccounts; ++i)
461 {
462 accounts.emplace_back("alice_" + std::to_string(fundedAccounts + i));
463 env.fund(jtx::XRP(param.initAmount), accounts.back());
464 }
465 env.close();
466 }
467
471 void
472 sendPayments(int newTxes)
473 {
474 int fundedAccounts = accounts.size();
475 assert(fundedAccounts >= newTxes);
477
478 // somewhat random but reproducible
479 int r = ledgerMaster.getClosedLedger()->seq() * 7;
480 int fromIdx = 0;
481 int toIdx = 0;
482 auto updateIdx = [&]() {
483 assert(fundedAccounts > senders.size());
484 fromIdx = (fromIdx + r) % fundedAccounts;
485 while (senders.contains(fromIdx))
486 fromIdx = (fromIdx + 1) % fundedAccounts;
487 senders.insert(fromIdx);
488 toIdx = (toIdx + (r * 2)) % fundedAccounts;
489 if (toIdx == fromIdx)
490 toIdx = (toIdx + 1) % fundedAccounts;
491 };
492
493 for (int i = 0; i < newTxes; ++i)
494 {
495 updateIdx();
496 env(pay(accounts[fromIdx],
497 accounts[toIdx],
498 jtx::drops(ledgerMaster.getClosedLedger()->fees().base) +
499 jtx::XRP(param.txAmount)),
503 }
504 env.close();
505 }
506
510 void
512 {
513 for (int i = 0; i < param.initLedgers - 1; ++i)
514 {
515 sendPayments(param.numTxPerLedger);
516 }
517 }
518
525};
526
533
542{
543public:
546 LedgerServer& server,
550 : env(suite, jtx::envconfig(), nullptr, beast::Severity::Disabled)
551 , app(env.app())
552 , ledgerMaster(env.app().getLedgerMaster())
553 , inboundLedgers(server.app.getLedgerMaster(), ledgerMaster, inboundBhvr)
554 , serverMsgHandler(server.app, server.app.getLedgerReplayer())
556 , replayer(
557 env.app(),
559 std::make_unique<TestPeerSetBuilder>(
562 behavior,
563 peerFeature))
564 {
565 }
566
567 void
569 {
570 ledgerMaster.storeLedger(l);
571 }
572
573 bool
574 haveLedgers(UInt256 const& finishLedgerHash, int totalReplay)
575 {
576 UInt256 hash = finishLedgerHash;
577 int i = 0;
578 for (; i < totalReplay; ++i)
579 {
580 auto const l = ledgerMaster.getLedgerByHash(hash);
581 if (!l)
582 return false;
583 hash = l->header().parentHash;
584 }
585 return true;
586 }
587
588 bool
589 waitForLedgers(UInt256 const& finishLedgerHash, int totalReplay)
590 {
591 int const totalRound = 100;
592 for (int i = 0; i < totalRound; ++i)
593 {
594 if (haveLedgers(finishLedgerHash, totalReplay))
595 return true;
596 if (i < totalRound - 1)
598 }
599 return false;
600 }
601
602 bool
604 {
605 int const totalRound = 100;
606 for (int i = 0; i < totalRound; ++i)
607 {
608 bool allDone = true;
609 {
610 std::unique_lock<std::mutex> const lock(replayer.mtx_);
611 for (auto const& t : replayer.tasks_)
612 {
613 if (!t->finished())
614 {
615 allDone = false;
616 break;
617 }
618 }
619 }
620 if (allDone)
621 return true;
622 if (i < totalRound - 1)
624 }
625 return false;
626 }
627
630 {
631 std::unique_lock<std::mutex> const lock(replayer.mtx_);
632 return replayer.tasks_;
633 }
634
636 findTask(UInt256 const& hash, int totalReplay)
637 {
638 std::unique_lock<std::mutex> const lock(replayer.mtx_);
639 auto i = std::ranges::find_if(replayer.tasks_, [&](auto const& t) {
640 return t->parameter_.finishHash == hash && t->parameter_.totalLedgers == totalReplay;
641 });
642 if (i == replayer.tasks_.end())
643 return {};
644 return *i;
645 }
646
649 {
650 std::unique_lock<std::mutex> const lock(replayer.mtx_);
651 return replayer.deltas_.size();
652 }
653
656 {
657 std::unique_lock<std::mutex> const lock(replayer.mtx_);
658 return replayer.skipLists_.size();
659 }
660
661 bool
663 {
664 std::unique_lock<std::mutex> const lock(replayer.mtx_);
665 return replayer.tasks_.size() == tasks && replayer.skipLists_.size() == skipLists &&
666 replayer.deltas_.size() == deltas;
667 }
668
671 {
672 std::unique_lock<std::mutex> const lock(replayer.mtx_);
673 auto i = replayer.skipLists_.find(hash);
674 if (i == replayer.skipLists_.end())
675 return {};
676 return i->second.lock();
677 }
678
681 {
682 std::unique_lock<std::mutex> const lock(replayer.mtx_);
683 auto i = replayer.deltas_.find(hash);
684 if (i == replayer.deltas_.end())
685 return {};
686 return i->second.lock();
687 }
688
689 template <typename T>
692 {
693 if (t->failed_)
694 return TaskStatus::Failed;
695 if (t->complete_)
697 return TaskStatus::NotDone;
698 }
699
700 bool
703 TaskStatus taskExpect,
704 TaskStatus skiplistExpect,
705 std::vector<TaskStatus> const& deltaExpects)
706 {
707 if (taskStatus(task) == taskExpect)
708 {
709 if (taskStatus(task->skipListAcquirer_) == skiplistExpect)
710 {
711 if (task->deltas_.size() == deltaExpects.size())
712 {
713 for (int i = 0; i < deltaExpects.size(); ++i)
714 {
715 if (taskStatus(task->deltas_[i]) != deltaExpects[i])
716 return false;
717 }
718 return true;
719 }
720 }
721 }
722 return false;
723 }
724
725 bool
727 UInt256 const& hash,
728 int totalReplay,
729 TaskStatus taskExpect,
730 TaskStatus skiplistExpect,
731 std::vector<TaskStatus> const& deltaExpects)
732 {
733 auto t = findTask(hash, totalReplay);
734 if (!t)
735 {
736 return taskExpect == TaskStatus::NotExist;
737 }
738
739 return asExpected(t, taskExpect, skiplistExpect, deltaExpects);
740 }
741
742 bool
744 UInt256 const& hash,
745 int totalReplay,
746 TaskStatus taskExpect,
747 TaskStatus skiplistExpect,
748 std::vector<TaskStatus> const& deltaExpects)
749 {
750 auto t = findTask(hash, totalReplay);
751 if (!t)
752 {
753 return taskExpect == TaskStatus::NotExist;
754 }
755
756 return asExpected(t, taskExpect, skiplistExpect, deltaExpects);
757 }
758
759 bool
761 UInt256 const& hash,
762 int totalReplay,
763 TaskStatus taskExpect,
764 TaskStatus skiplistExpect,
765 std::vector<TaskStatus> const& deltaExpects)
766 {
767 if (!waitForDone())
768 return false;
769
770 return checkStatus(hash, totalReplay, taskExpect, skiplistExpect, deltaExpects);
771 }
772
780};
781
782using beast::Severity;
783void
784logAll(LedgerServer& server, LedgerReplayClient& client, beast::Severity level = Severity::Trace)
785{
786 server.app.getLogs().threshold(level);
787 client.app.getLogs().threshold(level);
788}
789// logAll(net.server, net.client);
790
791/*
792 * Create a LedgerServer and a LedgerReplayClient
793 */
795{
798 LedgerServer::Parameter const& param,
802 : server(suite, param), client(suite, server, behavior, inboundBhvr, peerFeature)
803 {
804 // logAll(server, client);
805 }
808};
809
834
836{
837 void
839 {
840 testcase("ProofPath");
841 LedgerServer server(*this, {.initLedgers = 1});
842 auto const l = server.ledgerMaster.getClosedLedger();
843
844 {
845 // request, missing key
847 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
848 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
850 server.msgHandler.processProofPathRequest(request));
851 BEAST_EXPECT(reply->has_error());
852 BEAST_EXPECT(
853 server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::BadData);
854 }
855 {
856 // request, wrong hash
858 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
859 request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
860 UInt256 hash(1234567);
861 request->set_ledgerhash(hash.data(), hash.size());
863 server.msgHandler.processProofPathRequest(request));
864 BEAST_EXPECT(reply->has_error());
865 }
866
867 {
868 // good request
870 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
871 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
872 request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
873 // generate response
875 server.msgHandler.processProofPathRequest(request));
876 BEAST_EXPECT(!reply->has_error());
877 BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::Ok);
878
879 {
880 // bad reply: invalid hash/key sizes
881 {
882 // reply with undersized ledgerhash (31 bytes)
884 bad->set_ledgerhash(std::string(31, '\x01'));
885 BEAST_EXPECT(
886 server.msgHandler.processProofPathResponse(bad) ==
888 }
889 {
890 // reply with oversized ledgerhash (33 bytes)
892 bad->set_ledgerhash(std::string(33, '\x01'));
893 BEAST_EXPECT(
894 server.msgHandler.processProofPathResponse(bad) ==
896 }
897 {
898 // reply with empty ledgerhash
900 bad->set_ledgerhash(std::string());
901 BEAST_EXPECT(
902 server.msgHandler.processProofPathResponse(bad) ==
904 }
905 {
906 // reply with undersized key (31 bytes)
908 bad->set_key(std::string(31, '\x01'));
909 BEAST_EXPECT(
910 server.msgHandler.processProofPathResponse(bad) ==
912 }
913 {
914 // reply with oversized key (33 bytes)
916 bad->set_key(std::string(33, '\x01'));
917 BEAST_EXPECT(
918 server.msgHandler.processProofPathResponse(bad) ==
920 }
921 {
922 // reply with empty key
924 bad->set_key(std::string());
925 BEAST_EXPECT(
926 server.msgHandler.processProofPathResponse(bad) ==
928 }
929 }
930
931 {
932 // bad reply
933 // bad header
934 std::string r(reply->ledgerheader());
935 r.back()--;
936 reply->set_ledgerheader(r);
937 BEAST_EXPECT(
938 server.msgHandler.processProofPathResponse(reply) ==
940 r.back()++;
941 reply->set_ledgerheader(r);
942 BEAST_EXPECT(
943 server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::Ok);
944 // bad proof path
945 reply->mutable_path()->RemoveLast();
946 BEAST_EXPECT(
947 server.msgHandler.processProofPathResponse(reply) ==
949 }
950 }
951 }
952
953 void
955 {
956 testcase("ReplayDelta");
957 LedgerServer server(*this, {.initLedgers = 1});
958 auto const l = server.ledgerMaster.getClosedLedger();
959
960 {
961 // request, missing hash
964 server.msgHandler.processReplayDeltaRequest(request));
965 BEAST_EXPECT(reply->has_error());
966 BEAST_EXPECT(
967 server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::BadData);
968 // request, wrong hash
969 UInt256 hash(1234567);
970 request->set_ledgerhash(hash.data(), hash.size());
972 server.msgHandler.processReplayDeltaRequest(request));
973 BEAST_EXPECT(reply->has_error());
974 BEAST_EXPECT(
975 server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::BadData);
976 }
977
978 {
979 // good request
981 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
983 server.msgHandler.processReplayDeltaRequest(request));
984 BEAST_EXPECT(!reply->has_error());
985 BEAST_EXPECT(
986 server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::Ok);
987
988 {
989 // bad reply: invalid hash sizes
990 {
991 // reply with undersized ledgerhash (31 bytes)
993 bad->set_ledgerhash(std::string(31, '\x01'));
994 BEAST_EXPECT(
995 server.msgHandler.processReplayDeltaResponse(bad) ==
997 }
998 {
999 // reply with oversized ledgerhash (33 bytes)
1001 bad->set_ledgerhash(std::string(33, '\x01'));
1002 BEAST_EXPECT(
1003 server.msgHandler.processReplayDeltaResponse(bad) ==
1005 }
1006 {
1007 // reply with empty ledgerhash
1009 bad->set_ledgerhash(std::string());
1010 BEAST_EXPECT(
1011 server.msgHandler.processReplayDeltaResponse(bad) ==
1013 }
1014 }
1015
1016 {
1017 // bad reply
1018 // bad header
1019 std::string r(reply->ledgerheader());
1020 r.back()--;
1021 reply->set_ledgerheader(r);
1022 BEAST_EXPECT(
1023 server.msgHandler.processReplayDeltaResponse(reply) ==
1025 r.back()++;
1026 reply->set_ledgerheader(r);
1027 BEAST_EXPECT(
1028 server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::Ok);
1029 // bad txns
1030 reply->mutable_transaction()->RemoveLast();
1031 BEAST_EXPECT(
1032 server.msgHandler.processReplayDeltaResponse(reply) ==
1034 }
1035 }
1036 }
1037
1038 void
1040 {
1041 testcase("TruncatedLedgerHeader");
1042 LedgerServer server(*this, {.initLedgers = 1});
1043 auto const l = server.ledgerMaster.getClosedLedger();
1044
1045 auto runNoThrow = [this](auto fn, char const* what) {
1046 try
1047 {
1048 BEAST_EXPECT(fn() == ReplayMsgStatus::Malformed);
1049 }
1050 catch (std::exception const& e)
1051 {
1052 fail(
1053 std::format("processor threw on truncated header ({}): {}", what, e.what()),
1054 __FILE__,
1055 __LINE__);
1056 }
1057 catch (...)
1058 {
1059 fail(
1060 std::format("processor threw unknown exception ({}) on truncated header", what),
1061 __FILE__,
1062 __LINE__);
1063 }
1064 };
1065
1066 {
1068 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
1070 server.msgHandler.processReplayDeltaRequest(request));
1071 BEAST_EXPECT(!reply->has_error());
1072
1073 reply->set_ledgerheader(std::string(1, '\x00'));
1074 runNoThrow(
1075 [&] { return server.msgHandler.processReplayDeltaResponse(reply); }, "ReplayDelta");
1076 }
1077
1078 {
1080 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
1081 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
1082 request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
1084 server.msgHandler.processProofPathRequest(request));
1085 BEAST_EXPECT(!reply->has_error());
1086
1087 reply->set_ledgerheader(std::string(1, '\x00'));
1088 runNoThrow(
1089 [&] { return server.msgHandler.processProofPathResponse(reply); }, "ProofPath");
1090 }
1091 }
1092
1093 void
1095 {
1096 testcase("TaskParameter");
1097
1098 auto makeSkipList = [](int count) -> std::vector<UInt256> {
1100 sList.reserve(count);
1101 for (int i = 0; i < count; ++i)
1102 sList.emplace_back(i);
1103 return sList;
1104 };
1105
1107 BEAST_EXPECT(!tp10.update(UInt256(777), 5, makeSkipList(10)));
1108 BEAST_EXPECT(!tp10.update(UInt256(10), 5, makeSkipList(8)));
1109 BEAST_EXPECT(tp10.update(UInt256(10), 10, makeSkipList(10)));
1110
1111 // can merge to self
1112 BEAST_EXPECT(tp10.canMergeInto(tp10));
1113
1114 // smaller task
1116
1117 BEAST_EXPECT(tp9.canMergeInto(tp10));
1118 BEAST_EXPECT(!tp10.canMergeInto(tp9));
1119
1120 tp9.totalLedgers++;
1121 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1122 tp9.totalLedgers--;
1123 BEAST_EXPECT(tp9.canMergeInto(tp10));
1124
1126 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1128 BEAST_EXPECT(tp9.canMergeInto(tp10));
1129
1130 tp9.finishHash = UInt256(1234);
1131 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1132 tp9.finishHash = UInt256(9);
1133 BEAST_EXPECT(tp9.canMergeInto(tp10));
1134
1135 // larger task
1137 BEAST_EXPECT(tp20.update(UInt256(20), 20, makeSkipList(20)));
1138 BEAST_EXPECT(tp10.canMergeInto(tp20));
1139 BEAST_EXPECT(tp9.canMergeInto(tp20));
1140 BEAST_EXPECT(!tp20.canMergeInto(tp10));
1141 BEAST_EXPECT(!tp20.canMergeInto(tp9));
1142 }
1143
1144 void
1146 {
1147 testcase("config test");
1148 {
1149 Config const c;
1150 BEAST_EXPECT(c.ledgerReplay == false);
1151 }
1152
1153 {
1154 Config c;
1155 std::string const toLoad(R"xrpldConfig(
1156[ledger_replay]
11571
1158)xrpldConfig");
1159 c.loadFromString(toLoad);
1160 BEAST_EXPECT(c.ledgerReplay == true);
1161 }
1162
1163 {
1164 Config c;
1165 std::string const toLoad = R"xrpldConfig(
1166[ledger_replay]
11670
1168)xrpldConfig";
1170 BEAST_EXPECT(c.ledgerReplay == false);
1171 }
1172 }
1173
1174 void
1176 {
1177 testcase("handshake test");
1178 auto handshake = [&](bool client, bool server, bool expecting) -> bool {
1179 auto request = xrpl::makeRequest(true, false, client, false, false);
1180 HttpRequestType httpRequest;
1181 httpRequest.version(request.version());
1182 httpRequest.base() = request.base();
1183 bool const serverResult = peerFeatureEnabled(httpRequest, kFeatureLedgerReplay, server);
1184 if (serverResult != expecting)
1185 return false;
1186
1187 beast::ip::Address const addr = boost::asio::ip::make_address("172.1.1.100");
1188 jtx::Env serverEnv(*this);
1189 serverEnv.app().config().ledgerReplay = server;
1190 auto httpResp = xrpl::makeResponse(
1191 true, httpRequest, addr, addr, UInt256{1}, 1, {1, 0}, serverEnv.app());
1192 auto const clientResult = peerFeatureEnabled(httpResp, kFeatureLedgerReplay, client);
1193 return clientResult == expecting;
1194 };
1195
1196 BEAST_EXPECT(handshake(false, false, false));
1197 BEAST_EXPECT(handshake(false, true, false));
1198 BEAST_EXPECT(handshake(true, false, false));
1199 BEAST_EXPECT(handshake(true, true, true));
1200 }
1201
1202 void
1203 testAllLocal(int totalReplay)
1204 {
1205 testcase("local node has all the ledgers");
1206 auto psBhvr = PeerSetBehavior::DropAll;
1207 auto ilBhvr = InboundLedgersBehavior::DropAll;
1208 auto peerFeature = PeerFeature::None;
1209
1210 NetworkOfTwo net(*this, {.initLedgers = totalReplay + 1}, psBhvr, ilBhvr, peerFeature);
1211
1212 auto l = net.server.ledgerMaster.getClosedLedger();
1213 UInt256 const finalHash = l->header().hash;
1214 for (int i = 0; i < totalReplay; ++i)
1215 {
1216 BEAST_EXPECT(l);
1217 if (l)
1218 {
1219 net.client.ledgerMaster.storeLedger(l);
1220 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1221 }
1222 else
1223 {
1224 break;
1225 }
1226 }
1227
1228 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1229
1230 std::vector<TaskStatus> const deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1231 BEAST_EXPECT(net.client.waitAndCheckStatus(
1232 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1233
1234 // sweep
1235 net.client.replayer.sweep();
1236 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1237 }
1238
1239 void
1240 testAllInboundLedgers(int totalReplay)
1241 {
1242 testcase("all the ledgers from InboundLedgers");
1243 NetworkOfTwo net(
1244 *this,
1245 {.initLedgers = totalReplay + 1},
1249
1250 auto l = net.server.ledgerMaster.getClosedLedger();
1251 UInt256 const finalHash = l->header().hash;
1252 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1253
1254 std::vector<TaskStatus> const deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1255 BEAST_EXPECT(net.client.waitAndCheckStatus(
1256 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1257
1258 // sweep() cleans up skipLists_ and deltas_ by removing entries whose
1259 // weak_ptr can no longer be locked. Those weak_ptrs expire only when the
1260 // last shared_ptr holder releases the sub-task. The sole owner is the
1261 // LedgerReplayTask, but a JobQueue worker thread may still hold a
1262 // temporary shared_ptr to a sub-task (from wptr.lock()) while executing
1263 // the timer job that drove the task to completion. If sweep() runs before
1264 // that thread unwinds, the weak_ptr is still lockable and the map entry
1265 // is not removed. We retry until the worker thread finishes.
1266 auto waitForSweep = [&net]() {
1267 for (auto numAttempts = 0; numAttempts < 20; ++numAttempts)
1268 {
1269 net.client.replayer.sweep();
1270 if (net.client.countsAsExpected(0, 0, 0))
1271 {
1272 return true;
1273 }
1275 }
1276 return false;
1277 };
1278 BEAST_EXPECT(waitForSweep());
1279 }
1280
1281 void
1282 testPeerSetBehavior(PeerSetBehavior peerSetBehavior, int totalReplay = 4)
1283 {
1284 switch (peerSetBehavior)
1285 {
1287 testcase("good network");
1288 break;
1290 testcase("network drops 50% messages");
1291 break;
1293 testcase("network repeats all messages");
1294 break;
1295 default:
1296 return;
1297 }
1298
1299 NetworkOfTwo net(
1300 *this,
1301 {.initLedgers = totalReplay + 1},
1302 peerSetBehavior,
1305
1306 // feed client with start ledger since InboundLedgers drops all
1307 auto l = net.server.ledgerMaster.getClosedLedger();
1308 UInt256 const finalHash = l->header().hash;
1309 for (int i = 0; i < totalReplay - 1; ++i)
1310 {
1311 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1312 }
1313 net.client.ledgerMaster.storeLedger(l);
1314
1315 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1316
1317 std::vector<TaskStatus> const deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1318 BEAST_EXPECT(net.client.waitAndCheckStatus(
1319 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1320 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay));
1321
1322 // sweep
1323 net.client.replayer.sweep();
1324 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1325 }
1326
1327 void
1328 testStop()
1329 {
1330 testcase("stop before timeout");
1331 int const totalReplay = 3;
1332 NetworkOfTwo net(
1333 *this,
1334 {.initLedgers = totalReplay + 1},
1338
1339 auto l = net.server.ledgerMaster.getClosedLedger();
1340 UInt256 const finalHash = l->header().hash;
1341 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1342
1343 std::vector<TaskStatus> const deltaStatuses;
1344 BEAST_EXPECT(net.client.checkStatus(
1345 finalHash, totalReplay, TaskStatus::NotDone, TaskStatus::NotDone, deltaStatuses));
1346
1347 BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0));
1348 net.client.replayer.stop();
1349 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1350 }
1351
1352 void
1354 {
1355 testcase("SkipListAcquire bad reply");
1356 int const totalReplay = 3;
1357 NetworkOfTwo net(
1358 *this,
1359 {.initLedgers = totalReplay + 1 + 1},
1363
1364 auto l = net.server.ledgerMaster.getClosedLedger();
1365 UInt256 const finalHash = l->header().hash;
1366 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1367
1368 auto skipList = net.client.findSkipListAcquire(finalHash);
1369
1370 std::uint8_t payload[55] = {0x6A, 0x09, 0xE6, 0x67, 0xF3, 0xBC, 0xC9, 0x08, 0xB2};
1371 auto item = makeShamapitem(UInt256(12345), Slice(payload, sizeof(payload)));
1372 skipList->processData(l->seq(), item);
1373
1374 std::vector<TaskStatus> const deltaStatuses;
1375 BEAST_EXPECT(net.client.waitAndCheckStatus(
1376 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1377
1378 // add another task
1379 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1);
1380 BEAST_EXPECT(net.client.waitAndCheckStatus(
1381 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1382 BEAST_EXPECT(net.client.countsAsExpected(2, 1, 0));
1383 }
1384
1385 void
1387 {
1388 testcase("LedgerDeltaAcquire bad reply");
1389 int const totalReplay = 3;
1390 NetworkOfTwo net(
1391 *this,
1392 {.initLedgers = totalReplay + 1},
1396
1397 auto l = net.server.ledgerMaster.getClosedLedger();
1398 UInt256 const finalHash = l->header().hash;
1399 net.client.ledgerMaster.storeLedger(l);
1400 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1401
1402 auto delta = net.client.findLedgerDeltaAcquire(l->header().parentHash);
1403 delta->processData(
1404 l->header(), // wrong ledger info
1406 BEAST_EXPECT(net.client.taskStatus(delta) == TaskStatus::Failed);
1407 BEAST_EXPECT(
1408 net.client.taskStatus(net.client.findTask(finalHash, totalReplay)) ==
1410
1411 // add another task
1412 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1);
1413 BEAST_EXPECT(
1414 net.client.taskStatus(net.client.findTask(finalHash, totalReplay + 1)) ==
1416 }
1417
1418 void
1420 {
1421 testcase("Overlap tasks");
1422 int const totalReplay = 5;
1423 NetworkOfTwo net(
1424 *this,
1425 {.initLedgers = (totalReplay * 3) + 1},
1429 auto l = net.server.ledgerMaster.getClosedLedger();
1430 UInt256 const finalHash = l->header().hash;
1431 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1432 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1433 BEAST_EXPECT(net.client.waitAndCheckStatus(
1434 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1435 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay));
1436
1437 // same range, same reason
1438 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1439 BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1));
1440 // same range, different reason
1441 net.client.replayer.replay(InboundLedger::Reason::CONSENSUS, finalHash, totalReplay);
1442 BEAST_EXPECT(net.client.countsAsExpected(2, 1, totalReplay - 1));
1443
1444 // no overlap
1445 for (int i = 0; i < totalReplay + 2; ++i)
1446 {
1447 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1448 }
1449 auto finalHashEarly = l->header().hash;
1450 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHashEarly, totalReplay);
1451 BEAST_EXPECT(net.client.waitAndCheckStatus(
1452 finalHashEarly,
1453 totalReplay,
1456 deltaStatuses)); // deltaStatuses no change
1457 BEAST_EXPECT(net.client.waitForLedgers(finalHashEarly, totalReplay));
1458 BEAST_EXPECT(net.client.countsAsExpected(3, 2, 2 * (totalReplay - 1)));
1459
1460 // partial overlap
1461 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1462 auto finalHashMoreEarly = l->header().parentHash;
1463 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHashMoreEarly, totalReplay);
1464 BEAST_EXPECT(net.client.waitAndCheckStatus(
1465 finalHashMoreEarly,
1466 totalReplay,
1469 deltaStatuses)); // deltaStatuses no change
1470 BEAST_EXPECT(net.client.waitForLedgers(finalHashMoreEarly, totalReplay));
1471 BEAST_EXPECT(net.client.countsAsExpected(4, 3, (2 * (totalReplay - 1)) + 2));
1472
1473 // cover
1474 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay * 3);
1475 deltaStatuses = std::vector<TaskStatus>((totalReplay * 3) - 1, TaskStatus::Completed);
1476 BEAST_EXPECT(net.client.waitAndCheckStatus(
1477 finalHash,
1478 totalReplay * 3,
1481 deltaStatuses)); // deltaStatuses changed
1482 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay * 3));
1483 BEAST_EXPECT(net.client.countsAsExpected(5, 3, (totalReplay * 3) - 1));
1484
1485 // sweep
1486 net.client.replayer.sweep();
1487 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1488 }
1489
1490 void
1491 run() override
1492 {
1493 testProofPath();
1497 testConfig();
1498 testHandshake();
1499 testAllLocal(1);
1500 testAllLocal(3);
1507 testStop();
1511 }
1512};
1513
1515{
1516 void
1518 {
1519 testcase("SkipListAcquire timeout");
1520 int const totalReplay = 3;
1521 NetworkOfTwo net(
1522 *this,
1523 {.initLedgers = totalReplay + 1},
1527
1528 auto l = net.server.ledgerMaster.getClosedLedger();
1529 UInt256 const finalHash = l->header().hash;
1530 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1531
1532 std::vector<TaskStatus> const deltaStatuses;
1533 BEAST_EXPECT(net.client.waitAndCheckStatus(
1534 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1535
1536 // sweep
1537 BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0));
1538 net.client.replayer.sweep();
1539 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1540 }
1541
1542 void
1544 {
1545 testcase("LedgerDeltaAcquire timeout");
1546 int const totalReplay = 3;
1547 NetworkOfTwo net(
1548 *this,
1549 {.initLedgers = totalReplay + 1},
1553
1554 auto l = net.server.ledgerMaster.getClosedLedger();
1555 UInt256 const finalHash = l->header().hash;
1556 net.client.ledgerMaster.storeLedger(l);
1557 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1558
1559 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Failed);
1560 deltaStatuses.back() = TaskStatus::Completed; // in client ledgerMaster
1561 BEAST_EXPECT(net.client.waitAndCheckStatus(
1562 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Completed, deltaStatuses));
1563
1564 // sweep
1565 BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1));
1566 net.client.replayer.sweep();
1567 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1568 }
1569
1570 void
1571 run() override
1572 {
1575 }
1576};
1577
1579{
1580 void
1581 run() override
1582 {
1583 testcase("Acquire 1000 ledgers");
1584 int const totalReplay = 250;
1585 int const rounds = 4;
1586 NetworkOfTwo net(
1587 *this,
1588 {.initLedgers = (totalReplay * rounds) + 1},
1592
1593 std::vector<UInt256> finishHashes;
1594 auto l = net.server.ledgerMaster.getClosedLedger();
1595 for (int i = 0; i < rounds; ++i)
1596 {
1597 finishHashes.push_back(l->header().hash);
1598 for (int j = 0; j < totalReplay; ++j)
1599 {
1600 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1601 }
1602 }
1603 BEAST_EXPECT(finishHashes.size() == rounds);
1604
1605 for (int i = 0; i < rounds; ++i)
1606 {
1607 net.client.replayer.replay(
1608 InboundLedger::Reason::GENERIC, finishHashes[i], totalReplay);
1609 }
1610
1611 std::vector<TaskStatus> const deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1612 for (int i = 0; i < rounds; ++i)
1613 {
1614 BEAST_EXPECT(net.client.waitAndCheckStatus(
1615 finishHashes[i],
1616 totalReplay,
1619 deltaStatuses));
1620 }
1621
1622 BEAST_EXPECT(net.client.waitForLedgers(finishHashes[0], totalReplay * rounds));
1623 BEAST_EXPECT(net.client.countsAsExpected(rounds, rounds, rounds * (totalReplay - 1)));
1624
1625 // sweep
1626 net.client.replayer.sweep();
1627 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1628 }
1629};
1630
1633BEAST_DEFINE_TESTSUITE(LedgerReplayerTimeout, app, xrpl);
1634BEAST_DEFINE_TESTSUITE_MANUAL(LedgerReplayerLong, app, xrpl);
1635
1636} // namespace xrpl::test
T back(T... args)
A testsuite class.
Definition suite.h:52
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:554
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
Represents a JSON value.
Definition json_value.h:117
pointer data()
Definition base_uint.h:117
static constexpr std::size_t size()
Definition base_uint.h:548
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Manages the lifetime of inbound ledgers.
Tracks the current ledger and any ledgers in the process of closing.
std::shared_ptr< Ledger const > getClosedLedger()
The finalized ledger is the last closed/accepted ledger.
std::shared_ptr< Ledger const > getLedgerByHash(UInt256 const &hash)
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.
beast::Severity threshold() const
Definition Log.cpp:143
Supports data retrieval by managing a set of peers.
Definition PeerSet.h:30
virtual LedgerMaster & getLedgerMaster()=0
virtual Logs & getLogs()=0
Ledger replay client side.
LedgerReplayClient(beast::unit_test::Suite &suite, LedgerServer &server, PeerSetBehavior behavior=PeerSetBehavior::Good, InboundLedgersBehavior inboundBhvr=InboundLedgersBehavior::Good, PeerFeature peerFeature=PeerFeature::LedgerReplayEnabled)
TaskStatus taskStatus(std::shared_ptr< T > const &t)
std::vector< std::shared_ptr< LedgerReplayTask > > getTasks()
bool haveLedgers(UInt256 const &finishLedgerHash, int totalReplay)
bool asExpected(UInt256 const &hash, int totalReplay, TaskStatus taskExpect, TaskStatus skiplistExpect, std::vector< TaskStatus > const &deltaExpects)
LedgerReplayMsgHandler clientMsgHandler
std::shared_ptr< LedgerReplayTask > findTask(UInt256 const &hash, int totalReplay)
bool waitAndCheckStatus(UInt256 const &hash, int totalReplay, TaskStatus taskExpect, TaskStatus skiplistExpect, std::vector< TaskStatus > const &deltaExpects)
bool waitForLedgers(UInt256 const &finishLedgerHash, int totalReplay)
void addLedger(std::shared_ptr< Ledger const > const &l)
bool countsAsExpected(std::size_t tasks, std::size_t skipLists, std::size_t deltas)
bool checkStatus(UInt256 const &hash, int totalReplay, TaskStatus taskExpect, TaskStatus skiplistExpect, std::vector< TaskStatus > const &deltaExpects)
std::shared_ptr< SkipListAcquire > findSkipListAcquire(UInt256 const &hash)
LedgerReplayMsgHandler serverMsgHandler
bool asExpected(std::shared_ptr< LedgerReplayTask > const &task, TaskStatus taskExpect, TaskStatus skiplistExpect, std::vector< TaskStatus > const &deltaExpects)
std::shared_ptr< LedgerDeltaAcquire > findLedgerDeltaAcquire(UInt256 const &hash)
Simulate a network InboundLedgers.
bool gotLedgerData(LedgerHash const &ledgerHash, std::shared_ptr< Peer >, std::shared_ptr< protocol::TMLedgerData >) override
MagicInboundLedgers(LedgerMaster &ledgerSource, LedgerMaster &ledgerSink, InboundLedgersBehavior bhvr)
bool isFailure(UInt256 const &h) override
void onLedgerFetched() override
Called when a complete ledger is obtained.
std::shared_ptr< InboundLedger > find(LedgerHash const &hash) override
~MagicInboundLedgers() override=default
void logFailure(UInt256 const &h, std::uint32_t seq) override
void acquireAsync(UInt256 const &hash, std::uint32_t seq, InboundLedger::Reason reason) override
std::size_t fetchRate() override
Returns the rate of historical ledger fetches per minute.
std::shared_ptr< Ledger const > acquire(UInt256 const &hash, std::uint32_t seq, InboundLedger::Reason) override
void gotStaleData(std::shared_ptr< protocol::TMLedgerData > packet) override
LedgerReplayMsgHandler & local_
LedgerReplayMsgHandler & remote_
TestPeerSetBuilder(LedgerReplayMsgHandler &me, LedgerReplayMsgHandler &other, PeerSetBehavior bhvr, PeerFeature peerFeature)
std::unique_ptr< PeerSet > build() override
Simulate a network peer.
bool supportsFeature(ProtocolFeature f) const override
TestPeer(bool enableLedgerReplay)
bool hasLedger(UInt256 const &, std::uint32_t) const override
A transaction testing environment.
Definition Env.h:161
Application & app()
Definition Env.h:300
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:133
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:323
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition Env.cpp:302
beast::Journal const journal
Definition Env.h:204
Set the fee on a JTx.
Definition fee.h:20
Set the regular signature on a JTx.
Definition sig.h:19
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:18
Adds an inner Batch transaction to a JTx and autofills it.
Definition batch.h:91
T contains(T... args)
T emplace_back(T... args)
T find_if(T... args)
T format(T... args)
T insert(T... args)
T make_shared(T... args)
T make_unique(T... args)
boost::asio::ip::address Address
Definition IPAddress.h:20
Severity
Severity level / threshold of a Journal message.
Definition Journal.h:16
STL namespace.
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:232
json::Value outer(jtx::Account const &account, uint32_t seq, STAmount const &fee, std::uint32_t flags)
Build an outer Batch transaction JSON object.
Definition batch.cpp:55
XRPAmount calcBatchFee(jtx::Env const &env, uint32_t const &numSigners, uint32_t const &txns=0)
Calculate the expected outer Batch transaction fee.
Definition batch.cpp:37
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:14
XrpT const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
FeatureBitset testableAmendments()
Definition Env.h:92
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:38
static AutofillT const kAutofill
Definition tags.h:15
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
void logAll(LedgerServer &server, LedgerReplayClient &client, beast::Severity level=Severity::Trace)
BEAST_DEFINE_TESTSUITE_MANUAL(AMMCalc, app, xrpl)
static UInt256 ledgerHash(LedgerHeader const &info)
BEAST_DEFINE_TESTSUITE_PRIO(AccountDelete, app, xrpl, 2)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
HttpResponseType makeResponse(bool crawlPublic, HttpRequestType const &req, beast::ip::Address publicIp, beast::ip::Address remoteIp, UInt256 const &sharedValue, std::optional< std::uint32_t > networkID, ProtocolVersion protocol, Application &app)
Make http response.
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> RequestType
Make outbound http request.
static constexpr char kFeatureLedgerReplay[]
Definition Handshake.h:131
UInt256 LedgerHash
BaseUInt< 256 > UInt256
Definition base_uint.h:580
boost::intrusive_ptr< SHAMapItem > makeShamapitem(UInt256 const &tag, Slice data)
Definition SHAMapItem.h:148
boost::beast::http::request< boost::beast::http::dynamic_body > HttpRequestType
Definition Handoff.h:12
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:28
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:182
@ Malformed
Protocol-level violation; no honest peer would produce this.
@ BadData
Peer reported has_error() (legitimate "cannot fulfill" signal).
@ tesSUCCESS
Definition TER.h:250
T reserve(T... args)
T size(T... args)
T sleep_for(T... args)
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)
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
std::set< Peer::ID > const & getPeerIds() const override
get the set of ids of previously added peers
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
Set the sequence number on a JTx.
Definition seq.h:16
T to_string(T... args)
T what(T... args)