xrpld
Loading...
Searching...
No Matches
LedgerReplay_test.cpp
1#include <test/jtx/Account.h>
2#include <test/jtx/Env.h>
3#include <test/jtx/amount.h>
4#include <test/jtx/batch.h>
5#include <test/jtx/envconfig.h>
6#include <test/jtx/fee.h>
7#include <test/jtx/pay.h>
8#include <test/jtx/seq.h>
9#include <test/jtx/sig.h>
10#include <test/jtx/tags.h>
11#include <test/jtx/ter.h>
12
13#include <xrpld/app/ledger/BuildLedger.h>
14#include <xrpld/app/ledger/InboundLedger.h>
15#include <xrpld/app/ledger/InboundLedgers.h>
16#include <xrpld/app/ledger/LedgerMaster.h>
17#include <xrpld/app/ledger/LedgerReplay.h>
18#include <xrpld/app/ledger/LedgerReplayTask.h>
19#include <xrpld/app/ledger/LedgerReplayer.h>
20#include <xrpld/app/ledger/detail/LedgerDeltaAcquire.h>
21#include <xrpld/app/ledger/detail/LedgerReplayMsgHandler.h>
22#include <xrpld/app/ledger/detail/SkipListAcquire.h>
23#include <xrpld/core/Config.h>
24#include <xrpld/overlay/Message.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/net/IPEndpoint.h>
33#include <xrpl/beast/unit_test/suite.h>
34#include <xrpl/beast/utility/Journal.h>
35#include <xrpl/json/json_value.h>
36#include <xrpl/ledger/ApplyView.h>
37#include <xrpl/protocol/Indexes.h>
38#include <xrpl/protocol/KeyType.h>
39#include <xrpl/protocol/PublicKey.h>
40#include <xrpl/protocol/RippleLedgerHash.h>
41#include <xrpl/protocol/SecretKey.h>
42#include <xrpl/protocol/TER.h>
43#include <xrpl/protocol/TxFlags.h>
44#include <xrpl/resource/Charge.h>
45#include <xrpl/server/Handoff.h>
46#include <xrpl/shamap/SHAMapItem.h>
47
48#include <boost/asio/ip/address.hpp>
49
50#include <google/protobuf/message.h>
51
52#include <xrpl.pb.h>
53
54#include <algorithm>
55#include <atomic>
56#include <cassert>
57#include <chrono>
58#include <cstddef>
59#include <cstdint>
60#include <cstdlib>
61#include <exception>
62#include <format>
63#include <functional>
64#include <map>
65#include <memory>
66#include <mutex>
67#include <optional>
68#include <set>
69#include <string>
70#include <thread>
71#include <unordered_set>
72#include <vector>
73
74namespace xrpl::test {
75
77{
78 void
80 {
81 testcase("Replay ledger");
82
83 using namespace jtx;
84
85 // Build a ledger normally
86 auto const alice = Account("alice");
87 auto const bob = Account("bob");
88
89 Env env(*this);
90 env.fund(XRP(100000), alice, bob);
91 env.close();
92
93 LedgerMaster& ledgerMaster = env.app().getLedgerMaster();
94 auto const lastClosed = ledgerMaster.getClosedLedger();
95 auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
96
97 auto const replayed = buildLedger(
98 LedgerReplay(lastClosedParent, lastClosed), TapNone, env.app(), env.journal);
99
100 BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
101 }
102
103 void
105 {
106 testcase("Replay ledger with batch transactions");
107
108 using namespace jtx;
109
110 Env env(*this, testableAmendments());
111
112 auto const alice = Account("alice");
113 auto const bob = Account("bob");
114 env.fund(XRP(100000), alice, bob);
115 env.close();
116
117 auto const seq = env.seq(alice);
118 auto const batchFee = batch::calcBatchFee(env, 0, 2);
119 env(batch::outer(alice, seq, batchFee, tfAllOrNothing),
120 batch::Inner(pay(alice, bob, XRP(1)), seq + 1),
121 batch::Inner(pay(alice, bob, XRP(2)), seq + 2),
122 Ter(tesSUCCESS));
123 env.close();
124
125 LedgerMaster& ledgerMaster = env.app().getLedgerMaster();
126 auto const lastClosed = ledgerMaster.getClosedLedger();
127 auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
128
129 auto const replayed = buildLedger(
130 LedgerReplay(lastClosedParent, lastClosed), TapNone, env.app(), env.journal);
131
132 BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
133 }
134
135 void
136 run() override
137 {
140 }
141};
142
147
154{
155public:
163 ~MagicInboundLedgers() override = default;
164
167 {
169 return {};
170 if (auto l = ledgerSource.getLedgerByHash(hash); l)
171 {
172 ledgerSink.storeLedger(l);
173 return l;
174 }
175
176 return {};
177 }
178
179 void
180 acquireAsync(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason reason) override
181 {
182 }
183
185 find(LedgerHash const& hash) override
186 {
187 return {};
188 }
189
190 bool
192 LedgerHash const& ledgerHash,
195 {
196 return false;
197 }
198
199 void
203
204 void
205 logFailure(uint256 const& h, std::uint32_t seq) override
206 {
207 }
208
209 bool
210 isFailure(uint256 const& h) override
211 {
212 return false;
213 }
214
215 void
216 clearFailures() override
217 {
218 }
219
221 getInfo() override
222 {
223 return {};
224 }
225
227 fetchRate() override
228 {
229 return 0;
230 }
231
232 void
234 {
235 }
236
237 void
238 gotFetchPack() override
239 {
240 }
241 void
242 sweep() override
243 {
244 }
245
246 void
247 stop() override
248 {
249 }
250
251 size_t
252 cacheSize() override
253 {
254 return 0;
255 }
256
260};
261
266
272class TestPeer : public Peer
273{
274public:
275 TestPeer(bool enableLedgerReplay)
276 : ledgerReplayEnabled_(enableLedgerReplay)
278 {
279 }
280
281 void
283 {
284 }
285 [[nodiscard]] beast::ip::Endpoint
286 getRemoteAddress() const override
287 {
288 return {};
289 }
290 void
291 charge(resource::Charge const& fee, std::string const& context = {}) override
292 {
293 }
294 [[nodiscard]] id_t
295 id() const override
296 {
297 return 1234;
298 }
299 [[nodiscard]] bool
300 cluster() const override
301 {
302 return false;
303 }
304 [[nodiscard]] bool
305 isHighLatency() const override
306 {
307 return false;
308 }
309 [[nodiscard]] int
310 getScore(bool) const override
311 {
312 return 0;
313 }
314 [[nodiscard]] PublicKey const&
315 getNodePublic() const override
316 {
317 return nodePublicKey_;
318 }
320 json() override
321 {
322 return {};
323 }
324 [[nodiscard]] bool
329 [[nodiscard]] std::optional<std::size_t>
330 publisherListSequence(PublicKey const&) const override
331 {
332 return {};
333 }
334 void
336 {
337 }
338 [[nodiscard]] uint256
339 getClosedLedgerHash() const override
340 {
341 static uint256 const kHash{};
342 return kHash;
343 }
344 [[nodiscard]] bool
345 hasLedger(uint256 const& hash, std::uint32_t seq) const override
346 {
347 return true;
348 }
349 void
350 ledgerRange(std::uint32_t& minSeq, std::uint32_t& maxSeq) const override
351 {
352 }
353 [[nodiscard]] bool
354 hasTxSet(uint256 const& hash) const override
355 {
356 return false;
357 }
358 void
359 cycleStatus() override
360 {
361 }
362 bool
364 {
365 return false;
366 }
367 [[nodiscard]] bool
368 compressionEnabled() const override
369 {
370 return false;
371 }
372 void
373 sendTxQueue() override
374 {
375 }
376 void
377 addTxQueue(uint256 const&) override
378 {
379 }
380 void
381 removeTxQueue(uint256 const&) override
382 {
383 }
384 [[nodiscard]] bool
385 txReduceRelayEnabled() const override
386 {
387 return false;
388 }
389
390 [[nodiscard]] std::string const&
391 fingerprint() const override
392 {
393 return fingerprint_;
394 }
395
396 // NOLINTBEGIN(readability-identifier-naming)
400 // NOLINTEND(readability-identifier-naming)
401};
402
411
418struct TestPeerSet : public PeerSet
419{
423 PeerSetBehavior bhvr,
424 bool enableLedgerReplay)
425 : local(me)
426 , remote(other)
427 , dummyPeer(std::make_shared<TestPeer>(enableLedgerReplay))
428 , behavior(bhvr)
429 {
430 }
431
432 void
434 std::size_t limit,
435 std::function<bool(std::shared_ptr<Peer> const&)> hasItem,
436 std::function<void(std::shared_ptr<Peer> const&)> onPeerAdded) override
437 {
438 hasItem(dummyPeer);
439 onPeerAdded(dummyPeer);
440 }
441
442 void
444 ::google::protobuf::Message const& msg,
445 protocol::MessageType type,
446 std::shared_ptr<Peer> const& peer) override
447 {
449 return;
450
451 // Drop every other message deterministically. Alternating drops
452 // still exercise the timeout/retry path while guaranteeing every
453 // subtask eventually gets a reply.
455 return;
456
457 switch (type)
458 {
459 case protocol::mtPROOF_PATH_REQ: {
461 return;
463 dynamic_cast<protocol::TMProofPathRequest const&>(msg));
465 remote.processProofPathRequest(request));
466 local.processProofPathResponse(reply);
468 local.processProofPathResponse(reply);
469 break;
470 }
471 case protocol::mtREPLAY_DELTA_REQ: {
473 return;
475 dynamic_cast<protocol::TMReplayDeltaRequest const&>(msg));
477 remote.processReplayDeltaRequest(request));
478 local.processReplayDeltaResponse(reply);
480 local.processReplayDeltaResponse(reply);
481 break;
482 }
483 default:
484 return;
485 }
486 }
487
488 [[nodiscard]] std::set<Peer::id_t> const&
489 getPeerIds() const override
490 {
491 static std::set<Peer::id_t> const kEmptyPeers;
492 return kEmptyPeers;
493 }
494
500};
501
532
538{
540 {
542 int initAccounts = 10;
543 int initAmount = 1'000'000;
545 int txAmount = 10;
546 };
547
549 : env(suite)
550 , app(env.app())
551 , ledgerMaster(env.app().getLedgerMaster())
552 , msgHandler(env.app(), env.app().getLedgerReplayer())
553 , param(p)
554 {
555 assert(param.initLedgers > 0);
556 createAccounts(param.initAccounts);
558 app.getLogs().threshold(beast::Severity::Warning);
559 }
560
564 void
565 createAccounts(int newAccounts)
566 {
567 auto fundedAccounts = accounts.size();
568 for (int i = 0; i < newAccounts; ++i)
569 {
570 accounts.emplace_back("alice_" + std::to_string(fundedAccounts + i));
571 env.fund(jtx::XRP(param.initAmount), accounts.back());
572 }
573 env.close();
574 }
575
579 void
580 sendPayments(int newTxes)
581 {
582 int fundedAccounts = accounts.size();
583 assert(fundedAccounts >= newTxes);
585
586 // somewhat random but reproducible
587 int r = ledgerMaster.getClosedLedger()->seq() * 7;
588 int fromIdx = 0;
589 int toIdx = 0;
590 auto updateIdx = [&]() {
591 assert(fundedAccounts > senders.size());
592 fromIdx = (fromIdx + r) % fundedAccounts;
593 while (senders.contains(fromIdx))
594 fromIdx = (fromIdx + 1) % fundedAccounts;
595 senders.insert(fromIdx);
596 toIdx = (toIdx + (r * 2)) % fundedAccounts;
597 if (toIdx == fromIdx)
598 toIdx = (toIdx + 1) % fundedAccounts;
599 };
600
601 for (int i = 0; i < newTxes; ++i)
602 {
603 updateIdx();
604 env(pay(accounts[fromIdx],
605 accounts[toIdx],
606 jtx::drops(ledgerMaster.getClosedLedger()->fees().base) +
607 jtx::XRP(param.txAmount)),
611 }
612 env.close();
613 }
614
618 void
620 {
621 for (int i = 0; i < param.initLedgers - 1; ++i)
622 {
623 sendPayments(param.numTxPerLedger);
624 }
625 }
626
633};
634
641
650{
651public:
654 LedgerServer& server,
658 : env(suite, jtx::envconfig(), nullptr, beast::Severity::Disabled)
659 , app(env.app())
660 , ledgerMaster(env.app().getLedgerMaster())
661 , inboundLedgers(server.app.getLedgerMaster(), ledgerMaster, inboundBhvr)
662 , serverMsgHandler(server.app, server.app.getLedgerReplayer())
664 , replayer(
665 env.app(),
667 std::make_unique<TestPeerSetBuilder>(
670 behavior,
671 peerFeature))
672 {
673 }
674
675 void
677 {
678 ledgerMaster.storeLedger(l);
679 }
680
681 bool
682 haveLedgers(uint256 const& finishLedgerHash, int totalReplay)
683 {
684 uint256 hash = finishLedgerHash;
685 int i = 0;
686 for (; i < totalReplay; ++i)
687 {
688 auto const l = ledgerMaster.getLedgerByHash(hash);
689 if (!l)
690 return false;
691 hash = l->header().parentHash;
692 }
693 return true;
694 }
695
696 bool
697 waitForLedgers(uint256 const& finishLedgerHash, int totalReplay)
698 {
699 int const totalRound = 100;
700 for (int i = 0; i < totalRound; ++i)
701 {
702 if (haveLedgers(finishLedgerHash, totalReplay))
703 return true;
704 if (i < totalRound - 1)
706 }
707 return false;
708 }
709
710 bool
712 {
713 int const totalRound = 100;
714 for (int i = 0; i < totalRound; ++i)
715 {
716 bool allDone = true;
717 {
718 std::unique_lock<std::mutex> const lock(replayer.mtx_);
719 for (auto const& t : replayer.tasks_)
720 {
721 if (!t->finished())
722 {
723 allDone = false;
724 break;
725 }
726 }
727 }
728 if (allDone)
729 return true;
730 if (i < totalRound - 1)
732 }
733 return false;
734 }
735
738 {
739 std::unique_lock<std::mutex> const lock(replayer.mtx_);
740 return replayer.tasks_;
741 }
742
744 findTask(uint256 const& hash, int totalReplay)
745 {
746 std::unique_lock<std::mutex> const lock(replayer.mtx_);
747 auto i = std::ranges::find_if(replayer.tasks_, [&](auto const& t) {
748 return t->parameter_.finishHash == hash && t->parameter_.totalLedgers == totalReplay;
749 });
750 if (i == replayer.tasks_.end())
751 return {};
752 return *i;
753 }
754
757 {
758 std::unique_lock<std::mutex> const lock(replayer.mtx_);
759 return replayer.deltas_.size();
760 }
761
764 {
765 std::unique_lock<std::mutex> const lock(replayer.mtx_);
766 return replayer.skipLists_.size();
767 }
768
769 bool
771 {
772 std::unique_lock<std::mutex> const lock(replayer.mtx_);
773 return replayer.tasks_.size() == tasks && replayer.skipLists_.size() == skipLists &&
774 replayer.deltas_.size() == deltas;
775 }
776
779 {
780 std::unique_lock<std::mutex> const lock(replayer.mtx_);
781 auto i = replayer.skipLists_.find(hash);
782 if (i == replayer.skipLists_.end())
783 return {};
784 return i->second.lock();
785 }
786
789 {
790 std::unique_lock<std::mutex> const lock(replayer.mtx_);
791 auto i = replayer.deltas_.find(hash);
792 if (i == replayer.deltas_.end())
793 return {};
794 return i->second.lock();
795 }
796
797 template <typename T>
800 {
801 if (t->failed_)
802 return TaskStatus::Failed;
803 if (t->complete_)
805 return TaskStatus::NotDone;
806 }
807
808 bool
811 TaskStatus taskExpect,
812 TaskStatus skiplistExpect,
813 std::vector<TaskStatus> const& deltaExpects)
814 {
815 if (taskStatus(task) == taskExpect)
816 {
817 if (taskStatus(task->skipListAcquirer_) == skiplistExpect)
818 {
819 if (task->deltas_.size() == deltaExpects.size())
820 {
821 for (int i = 0; i < deltaExpects.size(); ++i)
822 {
823 if (taskStatus(task->deltas_[i]) != deltaExpects[i])
824 return false;
825 }
826 return true;
827 }
828 }
829 }
830 return false;
831 }
832
833 bool
835 uint256 const& hash,
836 int totalReplay,
837 TaskStatus taskExpect,
838 TaskStatus skiplistExpect,
839 std::vector<TaskStatus> const& deltaExpects)
840 {
841 auto t = findTask(hash, totalReplay);
842 if (!t)
843 {
844 return taskExpect == TaskStatus::NotExist;
845 }
846
847 return asExpected(t, taskExpect, skiplistExpect, deltaExpects);
848 }
849
850 bool
852 uint256 const& hash,
853 int totalReplay,
854 TaskStatus taskExpect,
855 TaskStatus skiplistExpect,
856 std::vector<TaskStatus> const& deltaExpects)
857 {
858 auto t = findTask(hash, totalReplay);
859 if (!t)
860 {
861 return taskExpect == TaskStatus::NotExist;
862 }
863
864 return asExpected(t, taskExpect, skiplistExpect, deltaExpects);
865 }
866
867 bool
869 uint256 const& hash,
870 int totalReplay,
871 TaskStatus taskExpect,
872 TaskStatus skiplistExpect,
873 std::vector<TaskStatus> const& deltaExpects)
874 {
875 if (!waitForDone())
876 return false;
877
878 return checkStatus(hash, totalReplay, taskExpect, skiplistExpect, deltaExpects);
879 }
880
888};
889
890using beast::Severity;
891void
892logAll(LedgerServer& server, LedgerReplayClient& client, beast::Severity level = Severity::Trace)
893{
894 server.app.getLogs().threshold(level);
895 client.app.getLogs().threshold(level);
896}
897// logAll(net.server, net.client);
898
899/*
900 * Create a LedgerServer and a LedgerReplayClient
901 */
903{
906 LedgerServer::Parameter const& param,
910 : server(suite, param), client(suite, server, behavior, inboundBhvr, peerFeature)
911 {
912 // logAll(server, client);
913 }
916};
917
942
944{
945 void
947 {
948 testcase("ProofPath");
949 LedgerServer server(*this, {.initLedgers = 1});
950 auto const l = server.ledgerMaster.getClosedLedger();
951
952 {
953 // request, missing key
955 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
956 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
958 server.msgHandler.processProofPathRequest(request));
959 BEAST_EXPECT(reply->has_error());
960 BEAST_EXPECT(
961 server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::BadData);
962 }
963 {
964 // request, wrong hash
966 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
967 request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
968 uint256 hash(1234567);
969 request->set_ledgerhash(hash.data(), hash.size());
971 server.msgHandler.processProofPathRequest(request));
972 BEAST_EXPECT(reply->has_error());
973 }
974
975 {
976 // good request
978 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
979 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
980 request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
981 // generate response
983 server.msgHandler.processProofPathRequest(request));
984 BEAST_EXPECT(!reply->has_error());
985 BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::Ok);
986
987 {
988 // bad reply: invalid hash/key sizes
989 {
990 // reply with undersized ledgerhash (31 bytes)
992 bad->set_ledgerhash(std::string(31, '\x01'));
993 BEAST_EXPECT(
994 server.msgHandler.processProofPathResponse(bad) ==
996 }
997 {
998 // reply with oversized ledgerhash (33 bytes)
1000 bad->set_ledgerhash(std::string(33, '\x01'));
1001 BEAST_EXPECT(
1002 server.msgHandler.processProofPathResponse(bad) ==
1004 }
1005 {
1006 // reply with empty ledgerhash
1008 bad->set_ledgerhash(std::string());
1009 BEAST_EXPECT(
1010 server.msgHandler.processProofPathResponse(bad) ==
1012 }
1013 {
1014 // reply with undersized key (31 bytes)
1016 bad->set_key(std::string(31, '\x01'));
1017 BEAST_EXPECT(
1018 server.msgHandler.processProofPathResponse(bad) ==
1020 }
1021 {
1022 // reply with oversized key (33 bytes)
1024 bad->set_key(std::string(33, '\x01'));
1025 BEAST_EXPECT(
1026 server.msgHandler.processProofPathResponse(bad) ==
1028 }
1029 {
1030 // reply with empty key
1032 bad->set_key(std::string());
1033 BEAST_EXPECT(
1034 server.msgHandler.processProofPathResponse(bad) ==
1036 }
1037 }
1038
1039 {
1040 // bad reply
1041 // bad header
1042 std::string r(reply->ledgerheader());
1043 r.back()--;
1044 reply->set_ledgerheader(r);
1045 BEAST_EXPECT(
1046 server.msgHandler.processProofPathResponse(reply) ==
1048 r.back()++;
1049 reply->set_ledgerheader(r);
1050 BEAST_EXPECT(
1051 server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::Ok);
1052 // bad proof path
1053 reply->mutable_path()->RemoveLast();
1054 BEAST_EXPECT(
1055 server.msgHandler.processProofPathResponse(reply) ==
1057 }
1058 }
1059 }
1060
1061 void
1063 {
1064 testcase("ReplayDelta");
1065 LedgerServer server(*this, {.initLedgers = 1});
1066 auto const l = server.ledgerMaster.getClosedLedger();
1067
1068 {
1069 // request, missing hash
1072 server.msgHandler.processReplayDeltaRequest(request));
1073 BEAST_EXPECT(reply->has_error());
1074 BEAST_EXPECT(
1075 server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::BadData);
1076 // request, wrong hash
1077 uint256 hash(1234567);
1078 request->set_ledgerhash(hash.data(), hash.size());
1080 server.msgHandler.processReplayDeltaRequest(request));
1081 BEAST_EXPECT(reply->has_error());
1082 BEAST_EXPECT(
1083 server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::BadData);
1084 }
1085
1086 {
1087 // good request
1089 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
1091 server.msgHandler.processReplayDeltaRequest(request));
1092 BEAST_EXPECT(!reply->has_error());
1093 BEAST_EXPECT(
1094 server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::Ok);
1095
1096 {
1097 // bad reply: invalid hash sizes
1098 {
1099 // reply with undersized ledgerhash (31 bytes)
1101 bad->set_ledgerhash(std::string(31, '\x01'));
1102 BEAST_EXPECT(
1103 server.msgHandler.processReplayDeltaResponse(bad) ==
1105 }
1106 {
1107 // reply with oversized ledgerhash (33 bytes)
1109 bad->set_ledgerhash(std::string(33, '\x01'));
1110 BEAST_EXPECT(
1111 server.msgHandler.processReplayDeltaResponse(bad) ==
1113 }
1114 {
1115 // reply with empty ledgerhash
1117 bad->set_ledgerhash(std::string());
1118 BEAST_EXPECT(
1119 server.msgHandler.processReplayDeltaResponse(bad) ==
1121 }
1122 }
1123
1124 {
1125 // bad reply
1126 // bad header
1127 std::string r(reply->ledgerheader());
1128 r.back()--;
1129 reply->set_ledgerheader(r);
1130 BEAST_EXPECT(
1131 server.msgHandler.processReplayDeltaResponse(reply) ==
1133 r.back()++;
1134 reply->set_ledgerheader(r);
1135 BEAST_EXPECT(
1136 server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::Ok);
1137 // bad txns
1138 reply->mutable_transaction()->RemoveLast();
1139 BEAST_EXPECT(
1140 server.msgHandler.processReplayDeltaResponse(reply) ==
1142 }
1143 }
1144 }
1145
1146 void
1148 {
1149 testcase("TruncatedLedgerHeader");
1150 LedgerServer server(*this, {.initLedgers = 1});
1151 auto const l = server.ledgerMaster.getClosedLedger();
1152
1153 auto runNoThrow = [this](auto fn, char const* what) {
1154 try
1155 {
1156 BEAST_EXPECT(fn() == ReplayMsgStatus::Malformed);
1157 }
1158 catch (std::exception const& e)
1159 {
1160 fail(
1161 std::format("processor threw on truncated header ({}): {}", what, e.what()),
1162 __FILE__,
1163 __LINE__);
1164 }
1165 catch (...)
1166 {
1167 fail(
1168 std::format("processor threw unknown exception ({}) on truncated header", what),
1169 __FILE__,
1170 __LINE__);
1171 }
1172 };
1173
1174 {
1176 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
1178 server.msgHandler.processReplayDeltaRequest(request));
1179 BEAST_EXPECT(!reply->has_error());
1180
1181 reply->set_ledgerheader(std::string(1, '\x00'));
1182 runNoThrow(
1183 [&] { return server.msgHandler.processReplayDeltaResponse(reply); }, "ReplayDelta");
1184 }
1185
1186 {
1188 request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
1189 request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
1190 request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
1192 server.msgHandler.processProofPathRequest(request));
1193 BEAST_EXPECT(!reply->has_error());
1194
1195 reply->set_ledgerheader(std::string(1, '\x00'));
1196 runNoThrow(
1197 [&] { return server.msgHandler.processProofPathResponse(reply); }, "ProofPath");
1198 }
1199 }
1200
1201 void
1203 {
1204 testcase("TaskParameter");
1205
1206 auto makeSkipList = [](int count) -> std::vector<uint256> {
1208 sList.reserve(count);
1209 for (int i = 0; i < count; ++i)
1210 sList.emplace_back(i);
1211 return sList;
1212 };
1213
1215 BEAST_EXPECT(!tp10.update(uint256(777), 5, makeSkipList(10)));
1216 BEAST_EXPECT(!tp10.update(uint256(10), 5, makeSkipList(8)));
1217 BEAST_EXPECT(tp10.update(uint256(10), 10, makeSkipList(10)));
1218
1219 // can merge to self
1220 BEAST_EXPECT(tp10.canMergeInto(tp10));
1221
1222 // smaller task
1224
1225 BEAST_EXPECT(tp9.canMergeInto(tp10));
1226 BEAST_EXPECT(!tp10.canMergeInto(tp9));
1227
1228 tp9.totalLedgers++;
1229 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1230 tp9.totalLedgers--;
1231 BEAST_EXPECT(tp9.canMergeInto(tp10));
1232
1234 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1236 BEAST_EXPECT(tp9.canMergeInto(tp10));
1237
1238 tp9.finishHash = uint256(1234);
1239 BEAST_EXPECT(!tp9.canMergeInto(tp10));
1240 tp9.finishHash = uint256(9);
1241 BEAST_EXPECT(tp9.canMergeInto(tp10));
1242
1243 // larger task
1245 BEAST_EXPECT(tp20.update(uint256(20), 20, makeSkipList(20)));
1246 BEAST_EXPECT(tp10.canMergeInto(tp20));
1247 BEAST_EXPECT(tp9.canMergeInto(tp20));
1248 BEAST_EXPECT(!tp20.canMergeInto(tp10));
1249 BEAST_EXPECT(!tp20.canMergeInto(tp9));
1250 }
1251
1252 void
1254 {
1255 testcase("config test");
1256 {
1257 Config const c;
1258 BEAST_EXPECT(c.ledgerReplay == false);
1259 }
1260
1261 {
1262 Config c;
1263 std::string const toLoad(R"xrpldConfig(
1264[ledger_replay]
12651
1266)xrpldConfig");
1267 c.loadFromString(toLoad);
1268 BEAST_EXPECT(c.ledgerReplay == true);
1269 }
1270
1271 {
1272 Config c;
1273 std::string const toLoad = R"xrpldConfig(
1274[ledger_replay]
12750
1276)xrpldConfig";
1278 BEAST_EXPECT(c.ledgerReplay == false);
1279 }
1280 }
1281
1282 void
1284 {
1285 testcase("handshake test");
1286 auto handshake = [&](bool client, bool server, bool expecting) -> bool {
1287 auto request = xrpl::makeRequest(true, false, client, false, false);
1288 http_request_type httpRequest;
1289 httpRequest.version(request.version());
1290 httpRequest.base() = request.base();
1291 bool const serverResult = peerFeatureEnabled(httpRequest, kFeatureLedgerReplay, server);
1292 if (serverResult != expecting)
1293 return false;
1294
1295 beast::ip::Address const addr = boost::asio::ip::make_address("172.1.1.100");
1296 jtx::Env serverEnv(*this);
1297 serverEnv.app().config().ledgerReplay = server;
1298 auto httpResp = xrpl::makeResponse(
1299 true, httpRequest, addr, addr, uint256{1}, 1, {1, 0}, serverEnv.app());
1300 auto const clientResult = peerFeatureEnabled(httpResp, kFeatureLedgerReplay, client);
1301 return clientResult == expecting;
1302 };
1303
1304 BEAST_EXPECT(handshake(false, false, false));
1305 BEAST_EXPECT(handshake(false, true, false));
1306 BEAST_EXPECT(handshake(true, false, false));
1307 BEAST_EXPECT(handshake(true, true, true));
1308 }
1309
1310 void
1311 testAllLocal(int totalReplay)
1312 {
1313 testcase("local node has all the ledgers");
1314 auto psBhvr = PeerSetBehavior::DropAll;
1315 auto ilBhvr = InboundLedgersBehavior::DropAll;
1316 auto peerFeature = PeerFeature::None;
1317
1318 NetworkOfTwo net(*this, {.initLedgers = totalReplay + 1}, psBhvr, ilBhvr, peerFeature);
1319
1320 auto l = net.server.ledgerMaster.getClosedLedger();
1321 uint256 const finalHash = l->header().hash;
1322 for (int i = 0; i < totalReplay; ++i)
1323 {
1324 BEAST_EXPECT(l);
1325 if (l)
1326 {
1327 net.client.ledgerMaster.storeLedger(l);
1328 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1329 }
1330 else
1331 {
1332 break;
1333 }
1334 }
1335
1336 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1337
1338 std::vector<TaskStatus> const deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1339 BEAST_EXPECT(net.client.waitAndCheckStatus(
1340 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1341
1342 // sweep
1343 net.client.replayer.sweep();
1344 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1345 }
1346
1347 void
1348 testAllInboundLedgers(int totalReplay)
1349 {
1350 testcase("all the ledgers from InboundLedgers");
1351 NetworkOfTwo net(
1352 *this,
1353 {.initLedgers = totalReplay + 1},
1357
1358 auto l = net.server.ledgerMaster.getClosedLedger();
1359 uint256 const finalHash = l->header().hash;
1360 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1361
1362 std::vector<TaskStatus> const deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1363 BEAST_EXPECT(net.client.waitAndCheckStatus(
1364 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1365
1366 // sweep() cleans up skipLists_ and deltas_ by removing entries whose
1367 // weak_ptr can no longer be locked. Those weak_ptrs expire only when the
1368 // last shared_ptr holder releases the sub-task. The sole owner is the
1369 // LedgerReplayTask, but a JobQueue worker thread may still hold a
1370 // temporary shared_ptr to a sub-task (from wptr.lock()) while executing
1371 // the timer job that drove the task to completion. If sweep() runs before
1372 // that thread unwinds, the weak_ptr is still lockable and the map entry
1373 // is not removed. We retry until the worker thread finishes.
1374 auto waitForSweep = [&net]() {
1375 for (auto numAttempts = 0; numAttempts < 20; ++numAttempts)
1376 {
1377 net.client.replayer.sweep();
1378 if (net.client.countsAsExpected(0, 0, 0))
1379 {
1380 return true;
1381 }
1383 }
1384 return false;
1385 };
1386 BEAST_EXPECT(waitForSweep());
1387 }
1388
1389 void
1390 testPeerSetBehavior(PeerSetBehavior peerSetBehavior, int totalReplay = 4)
1391 {
1392 switch (peerSetBehavior)
1393 {
1395 testcase("good network");
1396 break;
1398 testcase("network drops 50% messages");
1399 break;
1401 testcase("network repeats all messages");
1402 break;
1403 default:
1404 return;
1405 }
1406
1407 NetworkOfTwo net(
1408 *this,
1409 {.initLedgers = totalReplay + 1},
1410 peerSetBehavior,
1413
1414 // feed client with start ledger since InboundLedgers drops all
1415 auto l = net.server.ledgerMaster.getClosedLedger();
1416 uint256 const finalHash = l->header().hash;
1417 for (int i = 0; i < totalReplay - 1; ++i)
1418 {
1419 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1420 }
1421 net.client.ledgerMaster.storeLedger(l);
1422
1423 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1424
1425 std::vector<TaskStatus> const deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1426 BEAST_EXPECT(net.client.waitAndCheckStatus(
1427 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1428 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay));
1429
1430 // sweep
1431 net.client.replayer.sweep();
1432 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1433 }
1434
1435 void
1436 testStop()
1437 {
1438 testcase("stop before timeout");
1439 int const totalReplay = 3;
1440 NetworkOfTwo net(
1441 *this,
1442 {.initLedgers = totalReplay + 1},
1446
1447 auto l = net.server.ledgerMaster.getClosedLedger();
1448 uint256 const finalHash = l->header().hash;
1449 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1450
1451 std::vector<TaskStatus> const deltaStatuses;
1452 BEAST_EXPECT(net.client.checkStatus(
1453 finalHash, totalReplay, TaskStatus::NotDone, TaskStatus::NotDone, deltaStatuses));
1454
1455 BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0));
1456 net.client.replayer.stop();
1457 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1458 }
1459
1460 void
1462 {
1463 testcase("SkipListAcquire bad reply");
1464 int const totalReplay = 3;
1465 NetworkOfTwo net(
1466 *this,
1467 {.initLedgers = totalReplay + 1 + 1},
1471
1472 auto l = net.server.ledgerMaster.getClosedLedger();
1473 uint256 const finalHash = l->header().hash;
1474 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1475
1476 auto skipList = net.client.findSkipListAcquire(finalHash);
1477
1478 std::uint8_t payload[55] = {0x6A, 0x09, 0xE6, 0x67, 0xF3, 0xBC, 0xC9, 0x08, 0xB2};
1479 auto item = makeShamapitem(uint256(12345), Slice(payload, sizeof(payload)));
1480 skipList->processData(l->seq(), item);
1481
1482 std::vector<TaskStatus> const deltaStatuses;
1483 BEAST_EXPECT(net.client.waitAndCheckStatus(
1484 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1485
1486 // add another task
1487 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1);
1488 BEAST_EXPECT(net.client.waitAndCheckStatus(
1489 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1490 BEAST_EXPECT(net.client.countsAsExpected(2, 1, 0));
1491 }
1492
1493 void
1495 {
1496 testcase("LedgerDeltaAcquire bad reply");
1497 int const totalReplay = 3;
1498 NetworkOfTwo net(
1499 *this,
1500 {.initLedgers = totalReplay + 1},
1504
1505 auto l = net.server.ledgerMaster.getClosedLedger();
1506 uint256 const finalHash = l->header().hash;
1507 net.client.ledgerMaster.storeLedger(l);
1508 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1509
1510 auto delta = net.client.findLedgerDeltaAcquire(l->header().parentHash);
1511 delta->processData(
1512 l->header(), // wrong ledger info
1514 BEAST_EXPECT(net.client.taskStatus(delta) == TaskStatus::Failed);
1515 BEAST_EXPECT(
1516 net.client.taskStatus(net.client.findTask(finalHash, totalReplay)) ==
1518
1519 // add another task
1520 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay + 1);
1521 BEAST_EXPECT(
1522 net.client.taskStatus(net.client.findTask(finalHash, totalReplay + 1)) ==
1524 }
1525
1526 void
1528 {
1529 testcase("Overlap tasks");
1530 int const totalReplay = 5;
1531 NetworkOfTwo net(
1532 *this,
1533 {.initLedgers = (totalReplay * 3) + 1},
1537 auto l = net.server.ledgerMaster.getClosedLedger();
1538 uint256 const finalHash = l->header().hash;
1539 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1540 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1541 BEAST_EXPECT(net.client.waitAndCheckStatus(
1542 finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
1543 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay));
1544
1545 // same range, same reason
1546 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1547 BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1));
1548 // same range, different reason
1549 net.client.replayer.replay(InboundLedger::Reason::CONSENSUS, finalHash, totalReplay);
1550 BEAST_EXPECT(net.client.countsAsExpected(2, 1, totalReplay - 1));
1551
1552 // no overlap
1553 for (int i = 0; i < totalReplay + 2; ++i)
1554 {
1555 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1556 }
1557 auto finalHashEarly = l->header().hash;
1558 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHashEarly, totalReplay);
1559 BEAST_EXPECT(net.client.waitAndCheckStatus(
1560 finalHashEarly,
1561 totalReplay,
1564 deltaStatuses)); // deltaStatuses no change
1565 BEAST_EXPECT(net.client.waitForLedgers(finalHashEarly, totalReplay));
1566 BEAST_EXPECT(net.client.countsAsExpected(3, 2, 2 * (totalReplay - 1)));
1567
1568 // partial overlap
1569 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1570 auto finalHashMoreEarly = l->header().parentHash;
1571 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHashMoreEarly, totalReplay);
1572 BEAST_EXPECT(net.client.waitAndCheckStatus(
1573 finalHashMoreEarly,
1574 totalReplay,
1577 deltaStatuses)); // deltaStatuses no change
1578 BEAST_EXPECT(net.client.waitForLedgers(finalHashMoreEarly, totalReplay));
1579 BEAST_EXPECT(net.client.countsAsExpected(4, 3, (2 * (totalReplay - 1)) + 2));
1580
1581 // cover
1582 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay * 3);
1583 deltaStatuses = std::vector<TaskStatus>((totalReplay * 3) - 1, TaskStatus::Completed);
1584 BEAST_EXPECT(net.client.waitAndCheckStatus(
1585 finalHash,
1586 totalReplay * 3,
1589 deltaStatuses)); // deltaStatuses changed
1590 BEAST_EXPECT(net.client.waitForLedgers(finalHash, totalReplay * 3));
1591 BEAST_EXPECT(net.client.countsAsExpected(5, 3, (totalReplay * 3) - 1));
1592
1593 // sweep
1594 net.client.replayer.sweep();
1595 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1596 }
1597
1598 void
1599 run() override
1600 {
1601 testProofPath();
1605 testConfig();
1606 testHandshake();
1607 testAllLocal(1);
1608 testAllLocal(3);
1615 testStop();
1619 }
1620};
1621
1623{
1624 void
1626 {
1627 testcase("SkipListAcquire timeout");
1628 int const totalReplay = 3;
1629 NetworkOfTwo net(
1630 *this,
1631 {.initLedgers = totalReplay + 1},
1635
1636 auto l = net.server.ledgerMaster.getClosedLedger();
1637 uint256 const finalHash = l->header().hash;
1638 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1639
1640 std::vector<TaskStatus> const deltaStatuses;
1641 BEAST_EXPECT(net.client.waitAndCheckStatus(
1642 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Failed, deltaStatuses));
1643
1644 // sweep
1645 BEAST_EXPECT(net.client.countsAsExpected(1, 1, 0));
1646 net.client.replayer.sweep();
1647 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1648 }
1649
1650 void
1652 {
1653 testcase("LedgerDeltaAcquire timeout");
1654 int const totalReplay = 3;
1655 NetworkOfTwo net(
1656 *this,
1657 {.initLedgers = totalReplay + 1},
1661
1662 auto l = net.server.ledgerMaster.getClosedLedger();
1663 uint256 const finalHash = l->header().hash;
1664 net.client.ledgerMaster.storeLedger(l);
1665 net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay);
1666
1667 std::vector<TaskStatus> deltaStatuses(totalReplay - 1, TaskStatus::Failed);
1668 deltaStatuses.back() = TaskStatus::Completed; // in client ledgerMaster
1669 BEAST_EXPECT(net.client.waitAndCheckStatus(
1670 finalHash, totalReplay, TaskStatus::Failed, TaskStatus::Completed, deltaStatuses));
1671
1672 // sweep
1673 BEAST_EXPECT(net.client.countsAsExpected(1, 1, totalReplay - 1));
1674 net.client.replayer.sweep();
1675 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1676 }
1677
1678 void
1679 run() override
1680 {
1683 }
1684};
1685
1687{
1688 void
1689 run() override
1690 {
1691 testcase("Acquire 1000 ledgers");
1692 int const totalReplay = 250;
1693 int const rounds = 4;
1694 NetworkOfTwo net(
1695 *this,
1696 {.initLedgers = (totalReplay * rounds) + 1},
1700
1701 std::vector<uint256> finishHashes;
1702 auto l = net.server.ledgerMaster.getClosedLedger();
1703 for (int i = 0; i < rounds; ++i)
1704 {
1705 finishHashes.push_back(l->header().hash);
1706 for (int j = 0; j < totalReplay; ++j)
1707 {
1708 l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash);
1709 }
1710 }
1711 BEAST_EXPECT(finishHashes.size() == rounds);
1712
1713 for (int i = 0; i < rounds; ++i)
1714 {
1715 net.client.replayer.replay(
1716 InboundLedger::Reason::GENERIC, finishHashes[i], totalReplay);
1717 }
1718
1719 std::vector<TaskStatus> const deltaStatuses(totalReplay - 1, TaskStatus::Completed);
1720 for (int i = 0; i < rounds; ++i)
1721 {
1722 BEAST_EXPECT(net.client.waitAndCheckStatus(
1723 finishHashes[i],
1724 totalReplay,
1727 deltaStatuses));
1728 }
1729
1730 BEAST_EXPECT(net.client.waitForLedgers(finishHashes[0], totalReplay * rounds));
1731 BEAST_EXPECT(net.client.countsAsExpected(rounds, rounds, rounds * (totalReplay - 1)));
1732
1733 // sweep
1734 net.client.replayer.sweep();
1735 BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
1736 }
1737};
1738
1741BEAST_DEFINE_TESTSUITE(LedgerReplayerTimeout, app, xrpl);
1742BEAST_DEFINE_TESTSUITE_MANUAL(LedgerReplayerLong, app, xrpl);
1743
1744} // namespace xrpl::test
T back(T... args)
A version-independent IP address and port combination.
Definition IPEndpoint.h:24
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.
std::shared_ptr< Ledger const > getClosedLedger()
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
A public key.
Definition PublicKey.h:53
virtual LedgerMaster & getLedgerMaster()=0
virtual Logs & getLogs()=0
A consumption charge.
Definition Charge.h:13
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 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
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.
std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason) override
void acquireAsync(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason reason) override
bool gotLedgerData(LedgerHash const &ledgerHash, std::shared_ptr< Peer >, std::shared_ptr< protocol::TMLedgerData >) override
MagicInboundLedgers(LedgerMaster &ledgerSource, LedgerMaster &ledgerSink, InboundLedgersBehavior bhvr)
void onLedgerFetched() override
Called when a complete ledger is obtained.
std::shared_ptr< InboundLedger > find(LedgerHash const &hash) override
~MagicInboundLedgers() override=default
std::size_t fetchRate() override
Returns the rate of historical ledger fetches per minute.
void logFailure(uint256 const &h, std::uint32_t seq) override
bool isFailure(uint256 const &h) 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.
std::optional< std::size_t > publisherListSequence(PublicKey const &) const override
bool supportsFeature(ProtocolFeature f) const override
PublicKey const & getNodePublic() const override
std::string const & fingerprint() const override
void ledgerRange(std::uint32_t &minSeq, std::uint32_t &maxSeq) const override
bool compressionEnabled() const override
beast::ip::Endpoint getRemoteAddress() const override
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
uint256 getClosedLedgerHash() const override
int getScore(bool) const override
bool isHighLatency() const override
bool cluster() const override
void addTxQueue(uint256 const &) override
void removeTxQueue(uint256 const &) override
void send(std::shared_ptr< Message > const &m) override
bool hasRange(std::uint32_t uMin, std::uint32_t uMax) override
void setPublisherListSequence(PublicKey const &, std::size_t const) override
void charge(resource::Charge const &fee, std::string const &context={}) 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:66
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:210
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:53
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:35
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:37
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)
static uint256 ledgerHash(LedgerHeader const &info)
BEAST_DEFINE_TESTSUITE_MANUAL(AMMCalc, app, xrpl)
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
KeyType
Definition KeyType.h:8
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
static constexpr char kFeatureLedgerReplay[]
Definition Handshake.h:131
auto makeRequest(bool crawlPublic, bool comprEnabled, bool ledgerReplayEnabled, bool txReduceRelayEnabled, bool vpReduceRelayEnabled) -> request_type
Make outbound http request.
boost::intrusive_ptr< SHAMapItem > makeShamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:148
uint256 LedgerHash
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:28
http_response_type makeResponse(bool crawlPublic, http_request_type 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.
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).
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:12
BaseUInt< 256 > uint256
Definition base_uint.h:580
@ tesSUCCESS
Definition TER.h:245
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)
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
Set the sequence number on a JTx.
Definition seq.h:16
T to_string(T... args)
T what(T... args)