rippled
Loading...
Searching...
No Matches
Application.cpp
1#include <xrpld/app/consensus/RCLValidations.h>
2#include <xrpld/app/ledger/InboundLedgers.h>
3#include <xrpld/app/ledger/InboundTransactions.h>
4#include <xrpld/app/ledger/LedgerCleaner.h>
5#include <xrpld/app/ledger/LedgerMaster.h>
6#include <xrpld/app/ledger/LedgerReplayer.h>
7#include <xrpld/app/ledger/LedgerToJson.h>
8#include <xrpld/app/ledger/OpenLedger.h>
9#include <xrpld/app/ledger/OrderBookDB.h>
10#include <xrpld/app/ledger/PendingSaves.h>
11#include <xrpld/app/ledger/TransactionMaster.h>
12#include <xrpld/app/main/Application.h>
13#include <xrpld/app/main/BasicApp.h>
14#include <xrpld/app/main/DBInit.h>
15#include <xrpld/app/main/GRPCServer.h>
16#include <xrpld/app/main/LoadManager.h>
17#include <xrpld/app/main/NodeIdentity.h>
18#include <xrpld/app/main/NodeStoreScheduler.h>
19#include <xrpld/app/misc/AmendmentTable.h>
20#include <xrpld/app/misc/HashRouter.h>
21#include <xrpld/app/misc/LoadFeeTrack.h>
22#include <xrpld/app/misc/NetworkOPs.h>
23#include <xrpld/app/misc/SHAMapStore.h>
24#include <xrpld/app/misc/TxQ.h>
25#include <xrpld/app/misc/ValidatorKeys.h>
26#include <xrpld/app/misc/ValidatorSite.h>
27#include <xrpld/app/paths/PathRequests.h>
28#include <xrpld/app/rdb/RelationalDatabase.h>
29#include <xrpld/app/rdb/Wallet.h>
30#include <xrpld/app/tx/apply.h>
31#include <xrpld/core/DatabaseCon.h>
32#include <xrpld/overlay/Cluster.h>
33#include <xrpld/overlay/PeerReservationTable.h>
34#include <xrpld/overlay/PeerSet.h>
35#include <xrpld/overlay/make_Overlay.h>
36#include <xrpld/shamap/NodeFamily.h>
37
38#include <xrpl/basics/ByteUtilities.h>
39#include <xrpl/basics/ResolverAsio.h>
40#include <xrpl/basics/random.h>
41#include <xrpl/beast/asio/io_latency_probe.h>
42#include <xrpl/beast/core/LexicalCast.h>
43#include <xrpl/core/PerfLog.h>
44#include <xrpl/crypto/csprng.h>
45#include <xrpl/json/json_reader.h>
46#include <xrpl/nodestore/DummyScheduler.h>
47#include <xrpl/protocol/ApiVersion.h>
48#include <xrpl/protocol/BuildInfo.h>
49#include <xrpl/protocol/Feature.h>
50#include <xrpl/protocol/Protocol.h>
51#include <xrpl/protocol/STParsedJSON.h>
52#include <xrpl/resource/Fees.h>
53
54#include <boost/algorithm/string/predicate.hpp>
55#include <boost/asio/steady_timer.hpp>
56#include <boost/system/error_code.hpp>
57
58#include <date/date.h>
59
60#include <chrono>
61#include <condition_variable>
62#include <cstring>
63#include <fstream>
64#include <limits>
65#include <mutex>
66#include <optional>
67#include <utility>
68
69namespace xrpl {
70
71static void
72fixConfigPorts(Config& config, Endpoints const& endpoints);
73
74// VFALCO TODO Move the function definitions into the class declaration
75class ApplicationImp : public Application, public BasicApp
76{
77private:
79 {
80 private:
85
86 public:
91 boost::asio::io_context& ios)
92 : m_event(ev)
94 , m_probe(interval, ios)
95 , lastSample_{}
96 {
97 }
98
99 void
101 {
102 m_probe.sample(std::ref(*this));
103 }
104
105 template <class Duration>
106 void
107 operator()(Duration const& elapsed)
108 {
109 using namespace std::chrono;
110 auto const lastSample = ceil<milliseconds>(elapsed);
111
112 lastSample_ = lastSample;
113
114 if (lastSample >= 10ms)
115 m_event.notify(lastSample);
116 if (lastSample >= 500ms)
117 {
118 JLOG(m_journal.warn())
119 << "io_context latency = " << lastSample.count();
120 }
121 }
122
124 get() const
125 {
126 return lastSample_.load();
127 }
128
129 void
131 {
132 m_probe.cancel();
133 }
134
135 void
137 {
139 }
140 };
141
142public:
146
148
152
153 // Required by the SHAMapStore
155
162
167
169
172 // VFALCO TODO Make OrderBookDB abstract
196 boost::asio::steady_timer sweepTimer_;
197 boost::asio::steady_timer entropyTimer_;
198
203
204 boost::asio::signal_set m_signals;
205
207
209
211
213
215
216 //--------------------------------------------------------------------------
217
218 static std::size_t
220 {
221#if XRPL_SINGLE_IO_SERVICE_THREAD
222 return 1;
223#else
224
225 if (config.IO_WORKERS > 0)
226 return config.IO_WORKERS;
227
228 auto const cores = std::thread::hardware_concurrency();
229
230 // Use a single thread when running on under-provisioned systems
231 // or if we are configured to use minimal resources.
232 if ((cores == 1) || ((config.NODE_SIZE == 0) && (cores == 2)))
233 return 1;
234
235 // Otherwise, prefer six threads.
236 return 6;
237#endif
238 }
239
240 //--------------------------------------------------------------------------
241
247 , config_(std::move(config))
248 , logs_(std::move(logs))
249 , timeKeeper_(std::move(timeKeeper))
251 1 +
252 rand_int(
253 crypto_prng(),
254 std::numeric_limits<std::uint64_t>::max() - 1))
255 , m_journal(logs_->journal("Application"))
256
257 // PerfLog must be started before any other threads are launched.
258 , perfLog_(perf::make_PerfLog(
259 perf::setup_PerfLog(
260 config_->section("perf"),
261 config_->CONFIG_DIR),
262 *this,
263 logs_->journal("PerfLog"),
264 [this] { signalStop("PerfLog"); }))
265
266 , m_txMaster(*this)
267
269 config_->section(SECTION_INSIGHT),
270 logs_->journal("Collector")))
271
275 return 1;
276
277 if (config->WORKERS)
278 return config->WORKERS;
279
280 auto count =
281 static_cast<int>(std::thread::hardware_concurrency());
282
283 // Be more aggressive about the number of threads to use
284 // for the job queue if the server is configured as
285 // "large" or "huge" if there are enough cores.
286 if (config->NODE_SIZE >= 4 && count >= 16)
287 count = 6 + std::min(count, 8);
288 else if (config->NODE_SIZE >= 3 && count >= 8)
289 count = 4 + std::min(count, 6);
290 else
291 count = 2 + std::min(count, 4);
292
293 return count;
294 }(config_),
295 m_collectorManager->group("jobq"),
296 logs_->journal("JobQueue"),
297 *logs_,
298 *perfLog_))
299
301
303 *this,
305 logs_->journal("SHAMapStore")))
306
308 "NodeCache",
309 16384,
311 stopwatch(),
312 logs_->journal("TaggedCache"))
313
314 , cachedSLEs_(
315 "Cached SLEs",
316 0,
318 stopwatch(),
319 logs_->journal("CachedSLEs"))
320
322
324 m_collectorManager->collector(),
325 logs_->journal("Resource")))
326
327 , m_nodeStore(m_shaMapStore->makeNodeStore(
328 config_->PREFETCH_WORKERS > 0 ? config_->PREFETCH_WORKERS : 4))
329
331
332 , m_orderBookDB(*this)
333
334 , m_pathRequests(std::make_unique<PathRequests>(
335 *this,
336 logs_->journal("PathRequest"),
337 m_collectorManager->collector()))
338
339 , m_ledgerMaster(std::make_unique<LedgerMaster>(
340 *this,
341 stopwatch(),
342 m_collectorManager->collector(),
343 logs_->journal("LedgerMaster")))
344
346 make_LedgerCleaner(*this, logs_->journal("LedgerCleaner")))
347
348 // VFALCO NOTE must come before NetworkOPs to prevent a crash due
349 // to dependencies in the destructor.
350 //
352 *this,
353 stopwatch(),
354 m_collectorManager->collector()))
355
357 *this,
358 m_collectorManager->collector(),
359 [this](std::shared_ptr<SHAMap> const& set, bool fromAcquire) {
360 gotTXSet(set, fromAcquire);
361 }))
362
364 *this,
366 make_PeerSetBuilder(*this)))
367
369 "AcceptedLedger",
370 4,
372 stopwatch(),
373 logs_->journal("TaggedCache"))
374
376 *this,
377 stopwatch(),
378 config_->standalone(),
379 config_->NETWORK_QUORUM,
380 config_->START_VALID,
381 *m_jobQueue,
385 logs_->journal("NetworkOPs"),
386 m_collectorManager->collector()))
387
388 , cluster_(std::make_unique<Cluster>(logs_->journal("Overlay")))
389
391 logs_->journal("PeerReservationTable")))
392
394 std::make_unique<ManifestCache>(logs_->journal("ManifestCache")))
395
397 std::make_unique<ManifestCache>(logs_->journal("ManifestCache")))
398
403 config_->legacy("database_path"),
404 logs_->journal("ValidatorList"),
405 config_->VALIDATION_QUORUM))
406
408
410 *this,
412 *m_jobQueue,
416
417 , mFeeTrack(
418 std::make_unique<LoadFeeTrack>(logs_->journal("LoadManager")))
419
422 stopwatch()))
423
424 , mValidations(
425 ValidationParms(),
426 stopwatch(),
427 *this,
428 logs_->journal("Validations"))
429
430 , m_loadManager(make_LoadManager(*this, logs_->journal("LoadManager")))
431
432 , txQ_(
433 std::make_unique<TxQ>(setup_TxQ(*config_), logs_->journal("TxQ")))
434
436
438
440
441 , checkSigs_(true)
442
443 , m_resolver(
444 ResolverAsio::New(get_io_context(), logs_->journal("Resolver")))
445
447 m_collectorManager->collector()->make_event("ios_latency"),
448 logs_->journal("Application"),
452 {
454
455 add(m_resourceManager.get());
456
457 //
458 // VFALCO - READ THIS!
459 //
460 // Do not start threads, open sockets, or do any sort of "real work"
461 // inside the constructor. Put it in start instead. Or if you must,
462 // put it in setup (but everything in setup should be moved to start
463 // anyway.
464 //
465 // The reason is that the unit tests require an Application object to
466 // be created. But we don't actually start all the threads, sockets,
467 // and services when running the unit tests. Therefore anything which
468 // needs to be stopped will not get stopped correctly if it is
469 // started in this constructor.
470 //
471
472 add(ledgerCleaner_.get());
473 }
474
475 //--------------------------------------------------------------------------
476
477 bool
478 setup(boost::program_options::variables_map const& cmdline) override;
479 void
480 start(bool withTimers) override;
481 void
482 run() override;
483 void
484 signalStop(std::string msg) override;
485 bool
486 checkSigs() const override;
487 void
488 checkSigs(bool) override;
489 bool
490 isStopping() const override;
491 int
492 fdRequired() const override;
493
494 //--------------------------------------------------------------------------
495
497 instanceID() const override
498 {
499 return instanceCookie_;
500 }
501
502 Logs&
503 logs() override
504 {
505 return *logs_;
506 }
507
508 Config&
509 config() override
510 {
511 return *config_;
512 }
513
516 {
517 return *m_collectorManager;
518 }
519
520 Family&
521 getNodeFamily() override
522 {
523 return nodeFamily_;
524 }
525
527 timeKeeper() override
528 {
529 return *timeKeeper_;
530 }
531
532 JobQueue&
533 getJobQueue() override
534 {
535 return *m_jobQueue;
536 }
537
539 nodeIdentity() override
540 {
541 if (nodeIdentity_)
542 return *nodeIdentity_;
543
545 "Accessing Application::nodeIdentity() before it is initialized.");
546 }
547
549 getValidationPublicKey() const override
550 {
551 if (!validatorKeys_.keys)
552 return {};
553
554 return validatorKeys_.keys->publicKey;
555 }
556
558 getOPs() override
559 {
560 return *m_networkOPs;
561 }
562
563 virtual ServerHandler&
565 {
566 XRPL_ASSERT(
568 "xrpl::ApplicationImp::getServerHandler : non-null server "
569 "handle");
570 return *serverHandler_;
571 }
572
573 boost::asio::io_context&
574 getIOContext() override
575 {
576 return get_io_context();
577 }
578
580 getIOLatency() override
581 {
582 return m_io_latency_sampler.get();
583 }
584
587 {
588 return *m_ledgerMaster;
589 }
590
593 {
594 return *ledgerCleaner_;
595 }
596
599 {
600 return *m_ledgerReplayer;
601 }
602
605 {
606 return *m_inboundLedgers;
607 }
608
611 {
612 return *m_inboundTransactions;
613 }
614
617 {
619 }
620
621 void
622 gotTXSet(std::shared_ptr<SHAMap> const& set, bool fromAcquire)
623 {
624 if (set)
625 m_networkOPs->mapComplete(set, fromAcquire);
626 }
627
630 {
631 return m_txMaster;
632 }
633
635 getPerfLog() override
636 {
637 return *perfLog_;
638 }
639
640 NodeCache&
642 {
643 return m_tempNodeCache;
644 }
645
647 getNodeStore() override
648 {
649 return *m_nodeStore;
650 }
651
653 getMasterMutex() override
654 {
655 return m_masterMutex;
656 }
657
659 getLoadManager() override
660 {
661 return *m_loadManager;
662 }
663
666 {
667 return *m_resourceManager;
668 }
669
671 getOrderBookDB() override
672 {
673 return m_orderBookDB;
674 }
675
678 {
679 return *m_pathRequests;
680 }
681
683 cachedSLEs() override
684 {
685 return cachedSLEs_;
686 }
687
690 {
691 return *m_amendmentTable;
692 }
693
695 getFeeTrack() override
696 {
697 return *mFeeTrack;
698 }
699
701 getHashRouter() override
702 {
703 return *hashRouter_;
704 }
705
707 getValidations() override
708 {
709 return mValidations;
710 }
711
713 validators() override
714 {
715 return *validators_;
716 }
717
719 validatorSites() override
720 {
721 return *validatorSites_;
722 }
723
726 {
727 return *validatorManifests_;
728 }
729
732 {
733 return *publisherManifests_;
734 }
735
736 Cluster&
737 cluster() override
738 {
739 return *cluster_;
740 }
741
744 {
745 return *peerReservations_;
746 }
747
749 getSHAMapStore() override
750 {
751 return *m_shaMapStore;
752 }
753
755 pendingSaves() override
756 {
757 return pendingSaves_;
758 }
759
761 openLedger() override
762 {
763 return *openLedger_;
764 }
765
766 OpenLedger const&
767 openLedger() const override
768 {
769 return *openLedger_;
770 }
771
772 Overlay&
773 overlay() override
774 {
775 XRPL_ASSERT(
776 overlay_, "xrpl::ApplicationImp::overlay : non-null overlay");
777 return *overlay_;
778 }
779
780 TxQ&
781 getTxQ() override
782 {
783 XRPL_ASSERT(
784 txQ_, "xrpl::ApplicationImp::getTxQ : non-null transaction queue");
785 return *txQ_;
786 }
787
790 {
791 XRPL_ASSERT(
793 "xrpl::ApplicationImp::getRelationalDatabase : non-null "
794 "relational database");
795 return *mRelationalDatabase;
796 }
797
799 getWalletDB() override
800 {
801 XRPL_ASSERT(
802 mWalletDB,
803 "xrpl::ApplicationImp::getWalletDB : non-null wallet database");
804 return *mWalletDB;
805 }
806
807 bool
808 serverOkay(std::string& reason) override;
809
811 journal(std::string const& name) override;
812
813 //--------------------------------------------------------------------------
814
815 bool
817 {
818 XRPL_ASSERT(
819 mWalletDB.get() == nullptr,
820 "xrpl::ApplicationImp::initRelationalDatabase : null wallet "
821 "database");
822
823 try
824 {
827
828 // wallet database
830 setup.useGlobalPragma = false;
831
833 }
834 catch (std::exception const& e)
835 {
836 JLOG(m_journal.fatal())
837 << "Failed to initialize SQL databases: " << e.what();
838 return false;
839 }
840
841 return true;
842 }
843
844 bool
846 {
847 if (config_->doImport)
848 {
849 auto j = logs_->journal("NodeObject");
850 NodeStore::DummyScheduler dummyScheduler;
853 megabytes(config_->getValueFor(
855 dummyScheduler,
856 0,
858 j);
859
860 JLOG(j.warn()) << "Starting node import from '" << source->getName()
861 << "' to '" << m_nodeStore->getName() << "'.";
862
863 using namespace std::chrono;
864 auto const start = steady_clock::now();
865
866 m_nodeStore->importDatabase(*source);
867
868 auto const elapsed =
869 duration_cast<seconds>(steady_clock::now() - start);
870 JLOG(j.warn()) << "Node import from '" << source->getName()
871 << "' took " << elapsed.count() << " seconds.";
872 }
873
874 return true;
875 }
876
877 //--------------------------------------------------------------------------
878 //
879 // PropertyStream
880 //
881
882 void
884 {
885 }
886
887 //--------------------------------------------------------------------------
888
889 void
891 {
892 // Only start the timer if waitHandlerCounter_ is not yet joined.
893 if (auto optionalCountedHandler = waitHandlerCounter_.wrap(
894 [this](boost::system::error_code const& e) {
895 if (e.value() == boost::system::errc::success)
896 {
897 m_jobQueue->addJob(
898 jtSWEEP, "sweep", [this]() { doSweep(); });
899 }
900 // Recover as best we can if an unexpected error occurs.
901 if (e.value() != boost::system::errc::success &&
902 e.value() != boost::asio::error::operation_aborted)
903 {
904 // Try again later and hope for the best.
905 JLOG(m_journal.error())
906 << "Sweep timer got error '" << e.message()
907 << "'. Restarting timer.";
908 setSweepTimer();
909 }
910 }))
911 {
912 using namespace std::chrono;
913 sweepTimer_.expires_after(seconds{config_->SWEEP_INTERVAL.value_or(
914 config_->getValueFor(SizedItem::sweepInterval))});
915 sweepTimer_.async_wait(std::move(*optionalCountedHandler));
916 }
917 }
918
919 void
921 {
922 // Only start the timer if waitHandlerCounter_ is not yet joined.
923 if (auto optionalCountedHandler = waitHandlerCounter_.wrap(
924 [this](boost::system::error_code const& e) {
925 if (e.value() == boost::system::errc::success)
926 {
927 crypto_prng().mix_entropy();
928 setEntropyTimer();
929 }
930 // Recover as best we can if an unexpected error occurs.
931 if (e.value() != boost::system::errc::success &&
932 e.value() != boost::asio::error::operation_aborted)
933 {
934 // Try again later and hope for the best.
935 JLOG(m_journal.error())
936 << "Entropy timer got error '" << e.message()
937 << "'. Restarting timer.";
938 setEntropyTimer();
939 }
940 }))
941 {
942 using namespace std::chrono_literals;
943 entropyTimer_.expires_after(5min);
944 entropyTimer_.async_wait(std::move(*optionalCountedHandler));
945 }
946 }
947
948 void
950 {
951 if (!config_->standalone() &&
952 !getRelationalDatabase().transactionDbHasSpace(*config_))
953 {
954 signalStop("Out of transaction DB space");
955 }
956
957 // VFALCO NOTE Does the order of calls matter?
958 // VFALCO TODO fix the dependency inversion using an observer,
959 // have listeners register for "onSweep ()" notification.
960
961 {
962 std::shared_ptr<FullBelowCache const> const fullBelowCache =
963 nodeFamily_.getFullBelowCache();
964
965 std::shared_ptr<TreeNodeCache const> const treeNodeCache =
966 nodeFamily_.getTreeNodeCache();
967
968 std::size_t const oldFullBelowSize = fullBelowCache->size();
969 std::size_t const oldTreeNodeSize = treeNodeCache->size();
970
971 nodeFamily_.sweep();
972
973 JLOG(m_journal.debug())
974 << "NodeFamily::FullBelowCache sweep. Size before: "
975 << oldFullBelowSize
976 << "; size after: " << fullBelowCache->size();
977
978 JLOG(m_journal.debug())
979 << "NodeFamily::TreeNodeCache sweep. Size before: "
980 << oldTreeNodeSize << "; size after: " << treeNodeCache->size();
981 }
982 {
983 TaggedCache<uint256, Transaction> const& masterTxCache =
984 getMasterTransaction().getCache();
985
986 std::size_t const oldMasterTxSize = masterTxCache.size();
987
988 getMasterTransaction().sweep();
989
990 JLOG(m_journal.debug())
991 << "MasterTransaction sweep. Size before: " << oldMasterTxSize
992 << "; size after: " << masterTxCache.size();
993 }
994 {
995 // Does not appear to have an associated cache.
996 getNodeStore().sweep();
997 }
998 {
999 std::size_t const oldLedgerMasterCacheSize =
1000 getLedgerMaster().getFetchPackCacheSize();
1001
1002 getLedgerMaster().sweep();
1003
1004 JLOG(m_journal.debug())
1005 << "LedgerMaster sweep. Size before: "
1006 << oldLedgerMasterCacheSize << "; size after: "
1007 << getLedgerMaster().getFetchPackCacheSize();
1008 }
1009 {
1010 // NodeCache == TaggedCache<SHAMapHash, Blob>
1011 std::size_t const oldTempNodeCacheSize = getTempNodeCache().size();
1012
1013 getTempNodeCache().sweep();
1014
1015 JLOG(m_journal.debug())
1016 << "TempNodeCache sweep. Size before: " << oldTempNodeCacheSize
1017 << "; size after: " << getTempNodeCache().size();
1018 }
1019 {
1020 std::size_t const oldCurrentCacheSize =
1021 getValidations().sizeOfCurrentCache();
1022 std::size_t const oldSizeSeqEnforcesSize =
1023 getValidations().sizeOfSeqEnforcersCache();
1024 std::size_t const oldByLedgerSize =
1025 getValidations().sizeOfByLedgerCache();
1026 std::size_t const oldBySequenceSize =
1027 getValidations().sizeOfBySequenceCache();
1028
1029 getValidations().expire(m_journal);
1030
1031 JLOG(m_journal.debug())
1032 << "Validations Current expire. Size before: "
1033 << oldCurrentCacheSize
1034 << "; size after: " << getValidations().sizeOfCurrentCache();
1035
1036 JLOG(m_journal.debug())
1037 << "Validations SeqEnforcer expire. Size before: "
1038 << oldSizeSeqEnforcesSize << "; size after: "
1039 << getValidations().sizeOfSeqEnforcersCache();
1040
1041 JLOG(m_journal.debug())
1042 << "Validations ByLedger expire. Size before: "
1043 << oldByLedgerSize
1044 << "; size after: " << getValidations().sizeOfByLedgerCache();
1045
1046 JLOG(m_journal.debug())
1047 << "Validations BySequence expire. Size before: "
1048 << oldBySequenceSize
1049 << "; size after: " << getValidations().sizeOfBySequenceCache();
1050 }
1051 {
1052 std::size_t const oldInboundLedgersSize =
1053 getInboundLedgers().cacheSize();
1054
1055 getInboundLedgers().sweep();
1056
1057 JLOG(m_journal.debug())
1058 << "InboundLedgers sweep. Size before: "
1059 << oldInboundLedgersSize
1060 << "; size after: " << getInboundLedgers().cacheSize();
1061 }
1062 {
1063 size_t const oldTasksSize = getLedgerReplayer().tasksSize();
1064 size_t const oldDeltasSize = getLedgerReplayer().deltasSize();
1065 size_t const oldSkipListsSize = getLedgerReplayer().skipListsSize();
1066
1067 getLedgerReplayer().sweep();
1068
1069 JLOG(m_journal.debug())
1070 << "LedgerReplayer tasks sweep. Size before: " << oldTasksSize
1071 << "; size after: " << getLedgerReplayer().tasksSize();
1072
1073 JLOG(m_journal.debug())
1074 << "LedgerReplayer deltas sweep. Size before: "
1075 << oldDeltasSize
1076 << "; size after: " << getLedgerReplayer().deltasSize();
1077
1078 JLOG(m_journal.debug())
1079 << "LedgerReplayer skipLists sweep. Size before: "
1080 << oldSkipListsSize
1081 << "; size after: " << getLedgerReplayer().skipListsSize();
1082 }
1083 {
1084 std::size_t const oldAcceptedLedgerSize =
1085 m_acceptedLedgerCache.size();
1086
1087 m_acceptedLedgerCache.sweep();
1088
1089 JLOG(m_journal.debug())
1090 << "AcceptedLedgerCache sweep. Size before: "
1091 << oldAcceptedLedgerSize
1092 << "; size after: " << m_acceptedLedgerCache.size();
1093 }
1094 {
1095 std::size_t const oldCachedSLEsSize = cachedSLEs_.size();
1096
1097 cachedSLEs_.sweep();
1098
1099 JLOG(m_journal.debug())
1100 << "CachedSLEs sweep. Size before: " << oldCachedSLEsSize
1101 << "; size after: " << cachedSLEs_.size();
1102 }
1103
1104 // Set timer to do another sweep later.
1105 setSweepTimer();
1106 }
1107
1110 {
1111 return maxDisallowedLedger_;
1112 }
1113
1114 virtual std::optional<uint256> const&
1115 trapTxID() const override
1116 {
1117 return trapTxID_;
1118 }
1119
1120private:
1121 // For a newly-started validator, this is the greatest persisted ledger
1122 // and new validations must be greater than this.
1123 std::atomic<LedgerIndex> maxDisallowedLedger_{0};
1124
1125 void
1126 startGenesisLedger();
1127
1129 getLastFullLedger();
1130
1132 loadLedgerFromFile(std::string const& ledgerID);
1133
1134 bool
1135 loadOldLedger(
1136 std::string const& ledgerID,
1137 bool replay,
1138 bool isFilename,
1139 std::optional<uint256> trapTxID);
1140
1141 void
1142 setMaxDisallowedLedger();
1143};
1144
1145//------------------------------------------------------------------------------
1146
1147// TODO Break this up into smaller, more digestible initialization segments.
1148bool
1149ApplicationImp::setup(boost::program_options::variables_map const& cmdline)
1150{
1151 // We want to intercept CTRL-C and the standard termination signal SIGTERM
1152 // and terminate the process. This handler will NEVER be invoked twice.
1153 //
1154 // Note that async_wait is "one-shot": for each call, the handler will be
1155 // invoked exactly once, either when one of the registered signals in the
1156 // signal set occurs or the signal set is cancelled. Subsequent signals are
1157 // effectively ignored (technically, they are queued up, waiting for a call
1158 // to async_wait).
1159 m_signals.add(SIGINT);
1160 m_signals.add(SIGTERM);
1161 m_signals.async_wait(
1162 [this](boost::system::error_code const& ec, int signum) {
1163 // Indicates the signal handler has been aborted; do nothing
1164 if (ec == boost::asio::error::operation_aborted)
1165 return;
1166
1167 JLOG(m_journal.info()) << "Received signal " << signum;
1168
1169 if (signum == SIGTERM || signum == SIGINT)
1170 signalStop("Signal: " + to_string(signum));
1171 });
1172
1173 auto debug_log = config_->getDebugLogFile();
1174
1175 if (!debug_log.empty())
1176 {
1177 // Let debug messages go to the file but only WARNING or higher to
1178 // regular output (unless verbose)
1179
1180 if (!logs_->open(debug_log))
1181 std::cerr << "Can't open log file " << debug_log << '\n';
1182
1183 using namespace beast::severities;
1184 if (logs_->threshold() > kDebug)
1185 logs_->threshold(kDebug);
1186 }
1187
1188 JLOG(m_journal.info()) << "Process starting: "
1189 << BuildInfo::getFullVersionString()
1190 << ", Instance Cookie: " << instanceCookie_;
1191
1192 if (numberOfThreads(*config_) < 2)
1193 {
1194 JLOG(m_journal.warn()) << "Limited to a single I/O service thread by "
1195 "system configuration.";
1196 }
1197
1198 // Optionally turn off logging to console.
1199 logs_->silent(config_->silent());
1200
1201 if (!initRelationalDatabase() || !initNodeStore())
1202 return false;
1203
1204 if (!peerReservations_->load(getWalletDB()))
1205 {
1206 JLOG(m_journal.fatal()) << "Cannot find peer reservations!";
1207 return false;
1208 }
1209
1210 if (validatorKeys_.keys)
1211 setMaxDisallowedLedger();
1212
1213 // Configure the amendments the server supports
1214 {
1215 auto const supported = []() {
1216 auto const& amendments = detail::supportedAmendments();
1218 supported.reserve(amendments.size());
1219 for (auto const& [a, vote] : amendments)
1220 {
1221 auto const f = xrpl::getRegisteredFeature(a);
1222 XRPL_ASSERT(
1223 f, "xrpl::ApplicationImp::setup : registered feature");
1224 if (f)
1225 supported.emplace_back(a, *f, vote);
1226 }
1227 return supported;
1228 }();
1229 Section const& downVoted = config_->section(SECTION_VETO_AMENDMENTS);
1230
1231 Section const& upVoted = config_->section(SECTION_AMENDMENTS);
1232
1233 m_amendmentTable = make_AmendmentTable(
1234 *this,
1235 config().AMENDMENT_MAJORITY_TIME,
1236 supported,
1237 upVoted,
1238 downVoted,
1239 logs_->journal("Amendments"));
1240 }
1241
1242 Pathfinder::initPathTable();
1243
1244 auto const startUp = config_->START_UP;
1245 JLOG(m_journal.debug()) << "startUp: " << startUp;
1246 if (startUp == Config::FRESH)
1247 {
1248 JLOG(m_journal.info()) << "Starting new Ledger";
1249
1250 startGenesisLedger();
1251 }
1252 else if (
1253 startUp == Config::LOAD || startUp == Config::LOAD_FILE ||
1254 startUp == Config::REPLAY)
1255 {
1256 JLOG(m_journal.info()) << "Loading specified Ledger";
1257
1258 if (!loadOldLedger(
1259 config_->START_LEDGER,
1260 startUp == Config::REPLAY,
1261 startUp == Config::LOAD_FILE,
1262 config_->TRAP_TX_HASH))
1263 {
1264 JLOG(m_journal.error())
1265 << "The specified ledger could not be loaded.";
1266 if (config_->FAST_LOAD)
1267 {
1268 // Fall back to syncing from the network, such as
1269 // when there's no existing data.
1270 startGenesisLedger();
1271 }
1272 else
1273 {
1274 return false;
1275 }
1276 }
1277 }
1278 else if (startUp == Config::NETWORK)
1279 {
1280 // This should probably become the default once we have a stable
1281 // network.
1282 if (!config_->standalone())
1283 m_networkOPs->setNeedNetworkLedger();
1284
1285 startGenesisLedger();
1286 }
1287 else
1288 {
1289 startGenesisLedger();
1290 }
1291
1292 if (auto const& forcedRange = config().FORCED_LEDGER_RANGE_PRESENT)
1293 {
1294 m_ledgerMaster->setLedgerRangePresent(
1295 forcedRange->first, forcedRange->second);
1296 }
1297
1298 m_orderBookDB.setup(getLedgerMaster().getCurrentLedger());
1299
1300 nodeIdentity_ = getNodeIdentity(*this, cmdline);
1301
1302 if (!cluster_->load(config().section(SECTION_CLUSTER_NODES)))
1303 {
1304 JLOG(m_journal.fatal()) << "Invalid entry in cluster configuration.";
1305 return false;
1306 }
1307
1308 {
1309 if (validatorKeys_.configInvalid())
1310 return false;
1311
1312 if (!validatorManifests_->load(
1313 getWalletDB(),
1314 "ValidatorManifests",
1315 validatorKeys_.manifest,
1316 config().section(SECTION_VALIDATOR_KEY_REVOCATION).values()))
1317 {
1318 JLOG(m_journal.fatal()) << "Invalid configured validator manifest.";
1319 return false;
1320 }
1321
1322 publisherManifests_->load(getWalletDB(), "PublisherManifests");
1323
1324 // It is possible to have a valid ValidatorKeys object without
1325 // setting the signingKey or masterKey. This occurs if the
1326 // configuration file does not have either
1327 // SECTION_VALIDATOR_TOKEN or SECTION_VALIDATION_SEED section.
1328
1329 // masterKey for the configuration-file specified validator keys
1330 std::optional<PublicKey> localSigningKey;
1331 if (validatorKeys_.keys)
1332 localSigningKey = validatorKeys_.keys->publicKey;
1333
1334 // Setup trusted validators
1335 if (!validators_->load(
1336 localSigningKey,
1337 config().section(SECTION_VALIDATORS).values(),
1338 config().section(SECTION_VALIDATOR_LIST_KEYS).values(),
1339 config().VALIDATOR_LIST_THRESHOLD))
1340 {
1341 JLOG(m_journal.fatal())
1342 << "Invalid entry in validator configuration.";
1343 return false;
1344 }
1345 }
1346
1347 if (!validatorSites_->load(
1348 config().section(SECTION_VALIDATOR_LIST_SITES).values()))
1349 {
1350 JLOG(m_journal.fatal())
1351 << "Invalid entry in [" << SECTION_VALIDATOR_LIST_SITES << "]";
1352 return false;
1353 }
1354
1355 // Tell the AmendmentTable who the trusted validators are.
1356 m_amendmentTable->trustChanged(validators_->getQuorumKeys().second);
1357
1358 //----------------------------------------------------------------------
1359 //
1360 // Server
1361 //
1362 //----------------------------------------------------------------------
1363
1364 // VFALCO NOTE Unfortunately, in stand-alone mode some code still
1365 // foolishly calls overlay(). When this is fixed we can
1366 // move the instantiation inside a conditional:
1367 //
1368 // if (!config_.standalone())
1369 overlay_ = make_Overlay(
1370 *this,
1371 setup_Overlay(*config_),
1372 *serverHandler_,
1373 *m_resourceManager,
1374 *m_resolver,
1375 get_io_context(),
1376 *config_,
1377 m_collectorManager->collector());
1378 add(*overlay_); // add to PropertyStream
1379
1380 // start first consensus round
1381 if (!m_networkOPs->beginConsensus(
1382 m_ledgerMaster->getClosedLedger()->header().hash, {}))
1383 {
1384 JLOG(m_journal.fatal()) << "Unable to start consensus";
1385 return false;
1386 }
1387
1388 {
1389 try
1390 {
1391 auto setup = setup_ServerHandler(
1392 *config_, beast::logstream{m_journal.error()});
1393 setup.makeContexts();
1394 serverHandler_->setup(setup, m_journal);
1395 fixConfigPorts(*config_, serverHandler_->endpoints());
1396 }
1397 catch (std::exception const& e)
1398 {
1399 if (auto stream = m_journal.fatal())
1400 {
1401 stream << "Unable to setup server handler";
1402 if (std::strlen(e.what()) > 0)
1403 stream << ": " << e.what();
1404 }
1405 return false;
1406 }
1407 }
1408
1409 // Begin connecting to network.
1410 if (!config_->standalone())
1411 {
1412 // Should this message be here, conceptually? In theory this sort
1413 // of message, if displayed, should be displayed from PeerFinder.
1414 if (config_->PEER_PRIVATE && config_->IPS_FIXED.empty())
1415 {
1416 JLOG(m_journal.warn())
1417 << "No outbound peer connections will be made";
1418 }
1419
1420 // VFALCO NOTE the state timer resets the deadlock detector.
1421 //
1422 m_networkOPs->setStateTimer();
1423 }
1424 else
1425 {
1426 JLOG(m_journal.warn()) << "Running in standalone mode";
1427
1428 m_networkOPs->setStandAlone();
1429 }
1430
1431 if (config_->canSign())
1432 {
1433 JLOG(m_journal.warn()) << "*** The server is configured to allow the "
1434 "'sign' and 'sign_for'";
1435 JLOG(m_journal.warn()) << "*** commands. These commands have security "
1436 "implications and have";
1437 JLOG(m_journal.warn()) << "*** been deprecated. They will be removed "
1438 "in a future release of";
1439 JLOG(m_journal.warn()) << "*** rippled.";
1440 JLOG(m_journal.warn()) << "*** If you do not use them to sign "
1441 "transactions please edit your";
1442 JLOG(m_journal.warn())
1443 << "*** configuration file and remove the [enable_signing] stanza.";
1444 JLOG(m_journal.warn()) << "*** If you do use them to sign transactions "
1445 "please migrate to a";
1446 JLOG(m_journal.warn())
1447 << "*** standalone signing solution as soon as possible.";
1448 }
1449
1450 //
1451 // Execute start up rpc commands.
1452 //
1453 for (auto cmd : config_->section(SECTION_RPC_STARTUP).lines())
1454 {
1455 Json::Reader jrReader;
1456 Json::Value jvCommand;
1457
1458 if (!jrReader.parse(cmd, jvCommand))
1459 {
1460 JLOG(m_journal.fatal()) << "Couldn't parse entry in ["
1461 << SECTION_RPC_STARTUP << "]: '" << cmd;
1462 }
1463
1464 if (!config_->quiet())
1465 {
1466 JLOG(m_journal.fatal())
1467 << "Startup RPC: " << jvCommand << std::endl;
1468 }
1469
1470 Resource::Charge loadType = Resource::feeReferenceRPC;
1472 RPC::JsonContext context{
1473 {journal("RPCHandler"),
1474 *this,
1475 loadType,
1476 getOPs(),
1477 getLedgerMaster(),
1478 c,
1479 Role::ADMIN,
1480 {},
1481 {},
1482 RPC::apiMaximumSupportedVersion},
1483 jvCommand};
1484
1485 Json::Value jvResult;
1486 RPC::doCommand(context, jvResult);
1487
1488 if (!config_->quiet())
1489 {
1490 JLOG(m_journal.fatal()) << "Result: " << jvResult << std::endl;
1491 }
1492 }
1493
1494 validatorSites_->start();
1495
1496 return true;
1497}
1498
1499void
1500ApplicationImp::start(bool withTimers)
1501{
1502 JLOG(m_journal.info()) << "Application starting. Version is "
1503 << BuildInfo::getVersionString();
1504
1505 if (withTimers)
1506 {
1507 setSweepTimer();
1508 setEntropyTimer();
1509 }
1510
1511 m_io_latency_sampler.start();
1512 m_resolver->start();
1513 m_loadManager->start();
1514 m_shaMapStore->start();
1515 if (overlay_)
1516 overlay_->start();
1517
1518 if (grpcServer_->start())
1520 *config_, {{SECTION_PORT_GRPC, grpcServer_->getEndpoint()}});
1521
1522 ledgerCleaner_->start();
1523 perfLog_->start();
1524}
1525
1526void
1527ApplicationImp::run()
1528{
1529 if (!config_->standalone())
1530 {
1531 // VFALCO NOTE This seems unnecessary. If we properly refactor the load
1532 // manager then the stall detector can just always be
1533 // "armed"
1534 //
1535 getLoadManager().activateStallDetector();
1536 }
1537
1538 isTimeToStop.wait(false, std::memory_order_relaxed);
1539
1540 JLOG(m_journal.debug()) << "Application stopping";
1541
1542 m_io_latency_sampler.cancel_async();
1543
1544 // VFALCO Enormous hack, we have to force the probe to cancel
1545 // before we stop the io_context queue or else it never
1546 // unblocks in its destructor. The fix is to make all
1547 // io_objects gracefully handle exit so that we can
1548 // naturally return from io_context::run() instead of
1549 // forcing a call to io_context::stop()
1550 m_io_latency_sampler.cancel();
1551
1552 m_resolver->stop_async();
1553
1554 // NIKB This is a hack - we need to wait for the resolver to
1555 // stop. before we stop the io_server_queue or weird
1556 // things will happen.
1557 m_resolver->stop();
1558
1559 {
1560 try
1561 {
1562 sweepTimer_.cancel();
1563 }
1564 catch (boost::system::system_error const& e)
1565 {
1566 JLOG(m_journal.error())
1567 << "Application: sweepTimer cancel error: " << e.what();
1568 }
1569
1570 try
1571 {
1572 entropyTimer_.cancel();
1573 }
1574 catch (boost::system::system_error const& e)
1575 {
1576 JLOG(m_journal.error())
1577 << "Application: entropyTimer cancel error: " << e.what();
1578 }
1579 }
1580
1581 // Make sure that any waitHandlers pending in our timers are done
1582 // before we declare ourselves stopped.
1583 using namespace std::chrono_literals;
1584
1585 waitHandlerCounter_.join("Application", 1s, m_journal);
1586
1587 mValidations.flush();
1588
1589 validatorSites_->stop();
1590
1591 // TODO Store manifests in manifests.sqlite instead of wallet.db
1592 validatorManifests_->save(
1593 getWalletDB(), "ValidatorManifests", [this](PublicKey const& pubKey) {
1594 return validators().listed(pubKey);
1595 });
1596
1597 publisherManifests_->save(
1598 getWalletDB(), "PublisherManifests", [this](PublicKey const& pubKey) {
1599 return validators().trustedPublisher(pubKey);
1600 });
1601
1602 // The order of these stop calls is delicate.
1603 // Re-ordering them risks undefined behavior.
1604 m_loadManager->stop();
1605 m_shaMapStore->stop();
1606 m_jobQueue->stop();
1607 if (overlay_)
1608 overlay_->stop();
1609 grpcServer_->stop();
1610 m_networkOPs->stop();
1611 serverHandler_->stop();
1612 m_ledgerReplayer->stop();
1613 m_inboundTransactions->stop();
1614 m_inboundLedgers->stop();
1615 ledgerCleaner_->stop();
1616 m_nodeStore->stop();
1617 perfLog_->stop();
1618
1619 JLOG(m_journal.info()) << "Done.";
1620}
1621
1622void
1623ApplicationImp::signalStop(std::string msg)
1624{
1625 if (!isTimeToStop.test_and_set(std::memory_order_acquire))
1626 {
1627 if (msg.empty())
1628 JLOG(m_journal.warn()) << "Server stopping";
1629 else
1630 JLOG(m_journal.warn()) << "Server stopping: " << msg;
1631
1632 isTimeToStop.notify_all();
1633 }
1634}
1635
1636bool
1637ApplicationImp::checkSigs() const
1638{
1639 return checkSigs_;
1640}
1641
1642void
1643ApplicationImp::checkSigs(bool check)
1644{
1645 checkSigs_ = check;
1646}
1647
1648bool
1649ApplicationImp::isStopping() const
1650{
1651 return isTimeToStop.test(std::memory_order_relaxed);
1652}
1653
1654int
1655ApplicationImp::fdRequired() const
1656{
1657 // Standard handles, config file, misc I/O etc:
1658 int needed = 128;
1659
1660 // 2x the configured peer limit for peer connections:
1661 if (overlay_)
1662 needed += 2 * overlay_->limit();
1663
1664 // the number of fds needed by the backend (internally
1665 // doubled if online delete is enabled).
1666 needed += std::max(5, m_shaMapStore->fdRequired());
1667
1668 // One fd per incoming connection a port can accept, or
1669 // if no limit is set, assume it'll handle 256 clients.
1670 for (auto const& p : serverHandler_->setup().ports)
1671 needed += std::max(256, p.limit);
1672
1673 // The minimum number of file descriptors we need is 1024:
1674 return std::max(1024, needed);
1675}
1676
1677//------------------------------------------------------------------------------
1678
1679void
1680ApplicationImp::startGenesisLedger()
1681{
1682 std::vector<uint256> const initialAmendments =
1683 (config_->START_UP == Config::FRESH) ? m_amendmentTable->getDesired()
1685
1687 create_genesis, *config_, initialAmendments, nodeFamily_);
1688 m_ledgerMaster->storeLedger(genesis);
1689
1690 auto const next =
1691 std::make_shared<Ledger>(*genesis, timeKeeper().closeTime());
1692 next->updateSkipList();
1693 XRPL_ASSERT(
1694 next->header().seq < XRP_LEDGER_EARLIEST_FEES ||
1695 next->read(keylet::fees()),
1696 "xrpl::ApplicationImp::startGenesisLedger : valid ledger fees");
1697 next->setImmutable();
1698 openLedger_.emplace(next, cachedSLEs_, logs_->journal("OpenLedger"));
1699 m_ledgerMaster->storeLedger(next);
1700 m_ledgerMaster->switchLCL(next);
1701}
1702
1704ApplicationImp::getLastFullLedger()
1705{
1706 auto j = journal("Ledger");
1707
1708 try
1709 {
1710 auto const [ledger, seq, hash] = getLatestLedger(*this);
1711
1712 if (!ledger)
1713 return ledger;
1714
1715 XRPL_ASSERT(
1716 ledger->header().seq < XRP_LEDGER_EARLIEST_FEES ||
1717 ledger->read(keylet::fees()),
1718 "xrpl::ApplicationImp::getLastFullLedger : valid ledger fees");
1719 ledger->setImmutable();
1720
1721 if (getLedgerMaster().haveLedger(seq))
1722 ledger->setValidated();
1723
1724 if (ledger->header().hash == hash)
1725 {
1726 JLOG(j.trace()) << "Loaded ledger: " << hash;
1727 return ledger;
1728 }
1729
1730 if (auto stream = j.error())
1731 {
1732 stream << "Failed on ledger";
1733 Json::Value p;
1734 addJson(p, {*ledger, nullptr, LedgerFill::full});
1735 stream << p;
1736 }
1737
1738 return {};
1739 }
1740 catch (SHAMapMissingNode const& mn)
1741 {
1742 JLOG(j.warn()) << "Ledger in database: " << mn.what();
1743 return {};
1744 }
1745}
1746
1748ApplicationImp::loadLedgerFromFile(std::string const& name)
1749{
1750 try
1751 {
1752 std::ifstream ledgerFile(name, std::ios::in);
1753
1754 if (!ledgerFile)
1755 {
1756 JLOG(m_journal.fatal()) << "Unable to open file '" << name << "'";
1757 return nullptr;
1758 }
1759
1760 Json::Reader reader;
1761 Json::Value jLedger;
1762
1763 if (!reader.parse(ledgerFile, jLedger))
1764 {
1765 JLOG(m_journal.fatal()) << "Unable to parse ledger JSON";
1766 return nullptr;
1767 }
1768
1770
1771 // accept a wrapped ledger
1772 if (ledger.get().isMember("result"))
1773 ledger = ledger.get()["result"];
1774
1775 if (ledger.get().isMember("ledger"))
1776 ledger = ledger.get()["ledger"];
1777
1778 std::uint32_t seq = 1;
1779 auto closeTime = timeKeeper().closeTime();
1780 using namespace std::chrono_literals;
1781 auto closeTimeResolution = 30s;
1782 bool closeTimeEstimated = false;
1783 std::uint64_t totalDrops = 0;
1784
1785 if (ledger.get().isMember("accountState"))
1786 {
1787 if (ledger.get().isMember(jss::ledger_index))
1788 {
1789 seq = ledger.get()[jss::ledger_index].asUInt();
1790 }
1791
1792 if (ledger.get().isMember("close_time"))
1793 {
1794 using tp = NetClock::time_point;
1795 using d = tp::duration;
1796 closeTime = tp{d{ledger.get()["close_time"].asUInt()}};
1797 }
1798 if (ledger.get().isMember("close_time_resolution"))
1799 {
1800 using namespace std::chrono;
1801 closeTimeResolution =
1802 seconds{ledger.get()["close_time_resolution"].asUInt()};
1803 }
1804 if (ledger.get().isMember("close_time_estimated"))
1805 {
1806 closeTimeEstimated =
1807 ledger.get()["close_time_estimated"].asBool();
1808 }
1809 if (ledger.get().isMember("total_coins"))
1810 {
1811 totalDrops = beast::lexicalCastThrow<std::uint64_t>(
1812 ledger.get()["total_coins"].asString());
1813 }
1814
1815 ledger = ledger.get()["accountState"];
1816 }
1817
1818 if (!ledger.get().isArrayOrNull())
1819 {
1820 JLOG(m_journal.fatal()) << "State nodes must be an array";
1821 return nullptr;
1822 }
1823
1824 auto loadLedger =
1825 std::make_shared<Ledger>(seq, closeTime, *config_, nodeFamily_);
1826 loadLedger->setTotalDrops(totalDrops);
1827
1828 for (Json::UInt index = 0; index < ledger.get().size(); ++index)
1829 {
1830 Json::Value& entry = ledger.get()[index];
1831
1832 if (!entry.isObjectOrNull())
1833 {
1834 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
1835 return nullptr;
1836 }
1837
1838 uint256 uIndex;
1839
1840 if (!uIndex.parseHex(entry[jss::index].asString()))
1841 {
1842 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
1843 return nullptr;
1844 }
1845
1846 entry.removeMember(jss::index);
1847
1848 STParsedJSONObject stp("sle", ledger.get()[index]);
1849
1850 if (!stp.object || uIndex.isZero())
1851 {
1852 JLOG(m_journal.fatal()) << "Invalid entry in ledger";
1853 return nullptr;
1854 }
1855
1856 // VFALCO TODO This is the only place that
1857 // constructor is used, try to remove it
1858 STLedgerEntry sle(*stp.object, uIndex);
1859
1860 if (!loadLedger->addSLE(sle))
1861 {
1862 JLOG(m_journal.fatal())
1863 << "Couldn't add serialized ledger: " << uIndex;
1864 return nullptr;
1865 }
1866 }
1867
1868 loadLedger->stateMap().flushDirty(hotACCOUNT_NODE);
1869
1870 XRPL_ASSERT(
1871 loadLedger->header().seq < XRP_LEDGER_EARLIEST_FEES ||
1872 loadLedger->read(keylet::fees()),
1873 "xrpl::ApplicationImp::loadLedgerFromFile : valid ledger fees");
1874 loadLedger->setAccepted(
1875 closeTime, closeTimeResolution, !closeTimeEstimated);
1876
1877 return loadLedger;
1878 }
1879 catch (std::exception const& x)
1880 {
1881 JLOG(m_journal.fatal()) << "Ledger contains invalid data: " << x.what();
1882 return nullptr;
1883 }
1884}
1885
1886bool
1887ApplicationImp::loadOldLedger(
1888 std::string const& ledgerID,
1889 bool replay,
1890 bool isFileName,
1891 std::optional<uint256> trapTxID)
1892{
1893 try
1894 {
1895 std::shared_ptr<Ledger const> loadLedger, replayLedger;
1896
1897 if (isFileName)
1898 {
1899 if (!ledgerID.empty())
1900 loadLedger = loadLedgerFromFile(ledgerID);
1901 }
1902 else if (ledgerID.length() == 64)
1903 {
1904 uint256 hash;
1905
1906 if (hash.parseHex(ledgerID))
1907 {
1908 loadLedger = loadByHash(hash, *this);
1909
1910 if (!loadLedger)
1911 {
1912 // Try to build the ledger from the back end
1914 *this,
1915 hash,
1916 0,
1917 InboundLedger::Reason::GENERIC,
1918 stopwatch(),
1919 make_DummyPeerSet(*this));
1920 if (il->checkLocal())
1921 loadLedger = il->getLedger();
1922 }
1923 }
1924 }
1925 else if (ledgerID.empty() || boost::iequals(ledgerID, "latest"))
1926 {
1927 loadLedger = getLastFullLedger();
1928 }
1929 else
1930 {
1931 // assume by sequence
1932 std::uint32_t index;
1933
1934 if (beast::lexicalCastChecked(index, ledgerID))
1935 loadLedger = loadByIndex(index, *this);
1936 }
1937
1938 if (!loadLedger)
1939 return false;
1940
1941 if (replay)
1942 {
1943 // Replay a ledger close with same prior ledger and transactions
1944
1945 // this ledger holds the transactions we want to replay
1946 replayLedger = loadLedger;
1947
1948 JLOG(m_journal.info()) << "Loading parent ledger";
1949
1950 loadLedger = loadByHash(replayLedger->header().parentHash, *this);
1951 if (!loadLedger)
1952 {
1953 JLOG(m_journal.info())
1954 << "Loading parent ledger from node store";
1955
1956 // Try to build the ledger from the back end
1958 *this,
1959 replayLedger->header().parentHash,
1960 0,
1961 InboundLedger::Reason::GENERIC,
1962 stopwatch(),
1963 make_DummyPeerSet(*this));
1964
1965 if (il->checkLocal())
1966 loadLedger = il->getLedger();
1967
1968 if (!loadLedger)
1969 {
1970 // LCOV_EXCL_START
1971 JLOG(m_journal.fatal()) << "Replay ledger missing/damaged";
1972 UNREACHABLE(
1973 "xrpl::ApplicationImp::loadOldLedger : replay ledger "
1974 "missing/damaged");
1975 return false;
1976 // LCOV_EXCL_STOP
1977 }
1978 }
1979 }
1980 using namespace std::chrono_literals;
1981 using namespace date;
1982 static constexpr NetClock::time_point ledgerWarnTimePoint{
1983 sys_days{January / 1 / 2018} - sys_days{January / 1 / 2000}};
1984 if (loadLedger->header().closeTime < ledgerWarnTimePoint)
1985 {
1986 JLOG(m_journal.fatal())
1987 << "\n\n*** WARNING ***\n"
1988 "You are replaying a ledger from before "
1989 << to_string(ledgerWarnTimePoint)
1990 << " UTC.\n"
1991 "This replay will not handle your ledger as it was "
1992 "originally "
1993 "handled.\nConsider running an earlier version of rippled "
1994 "to "
1995 "get the older rules.\n*** CONTINUING ***\n";
1996 }
1997
1998 JLOG(m_journal.info()) << "Loading ledger " << loadLedger->header().hash
1999 << " seq:" << loadLedger->header().seq;
2000
2001 if (loadLedger->header().accountHash.isZero())
2002 {
2003 // LCOV_EXCL_START
2004 JLOG(m_journal.fatal()) << "Ledger is empty.";
2005 UNREACHABLE(
2006 "xrpl::ApplicationImp::loadOldLedger : ledger is empty");
2007 return false;
2008 // LCOV_EXCL_STOP
2009 }
2010
2011 if (!loadLedger->walkLedger(journal("Ledger"), true))
2012 {
2013 // LCOV_EXCL_START
2014 JLOG(m_journal.fatal()) << "Ledger is missing nodes.";
2015 UNREACHABLE(
2016 "xrpl::ApplicationImp::loadOldLedger : ledger is missing "
2017 "nodes");
2018 return false;
2019 // LCOV_EXCL_STOP
2020 }
2021
2022 if (!loadLedger->assertSensible(journal("Ledger")))
2023 {
2024 // LCOV_EXCL_START
2025 JLOG(m_journal.fatal()) << "Ledger is not sensible.";
2026 UNREACHABLE(
2027 "xrpl::ApplicationImp::loadOldLedger : ledger is not "
2028 "sensible");
2029 return false;
2030 // LCOV_EXCL_STOP
2031 }
2032
2033 m_ledgerMaster->setLedgerRangePresent(
2034 loadLedger->header().seq, loadLedger->header().seq);
2035
2036 m_ledgerMaster->switchLCL(loadLedger);
2037 loadLedger->setValidated();
2038 m_ledgerMaster->setFullLedger(loadLedger, true, false);
2039 openLedger_.emplace(
2040 loadLedger, cachedSLEs_, logs_->journal("OpenLedger"));
2041
2042 if (replay)
2043 {
2044 // inject transaction(s) from the replayLedger into our open ledger
2045 // and build replay structure
2046 auto replayData =
2047 std::make_unique<LedgerReplay>(loadLedger, replayLedger);
2048
2049 for (auto const& [_, tx] : replayData->orderedTxns())
2050 {
2051 (void)_;
2052 auto txID = tx->getTransactionID();
2053 if (trapTxID == txID)
2054 {
2055 trapTxID_ = txID;
2056 JLOG(m_journal.debug()) << "Trap transaction set: " << txID;
2057 }
2058
2060 tx->add(*s);
2061
2062 forceValidity(getHashRouter(), txID, Validity::SigGoodOnly);
2063
2064 openLedger_->modify(
2065 [&txID, &s](OpenView& view, beast::Journal j) {
2066 view.rawTxInsert(txID, std::move(s), nullptr);
2067 return true;
2068 });
2069 }
2070
2071 m_ledgerMaster->takeReplay(std::move(replayData));
2072
2073 if (trapTxID && !trapTxID_)
2074 {
2075 JLOG(m_journal.fatal())
2076 << "Ledger " << replayLedger->header().seq
2077 << " does not contain the transaction hash " << *trapTxID;
2078 return false;
2079 }
2080 }
2081 }
2082 catch (SHAMapMissingNode const& mn)
2083 {
2084 JLOG(m_journal.fatal())
2085 << "While loading specified ledger: " << mn.what();
2086 return false;
2087 }
2088 catch (boost::bad_lexical_cast&)
2089 {
2090 JLOG(m_journal.fatal())
2091 << "Ledger specified '" << ledgerID << "' is not valid";
2092 return false;
2093 }
2094
2095 return true;
2096}
2097
2098bool
2099ApplicationImp::serverOkay(std::string& reason)
2100{
2101 if (!config().ELB_SUPPORT)
2102 return true;
2103
2104 if (isStopping())
2105 {
2106 reason = "Server is shutting down";
2107 return false;
2108 }
2109
2110 if (getOPs().isNeedNetworkLedger())
2111 {
2112 reason = "Not synchronized with network yet";
2113 return false;
2114 }
2115
2116 if (getOPs().isAmendmentBlocked())
2117 {
2118 reason = "Server version too old";
2119 return false;
2120 }
2121
2122 if (getOPs().isUNLBlocked())
2123 {
2124 reason = "No valid validator list available";
2125 return false;
2126 }
2127
2128 if (getOPs().getOperatingMode() < OperatingMode::SYNCING)
2129 {
2130 reason = "Not synchronized with network";
2131 return false;
2132 }
2133
2134 if (!getLedgerMaster().isCaughtUp(reason))
2135 return false;
2136
2137 if (getFeeTrack().isLoadedLocal())
2138 {
2139 reason = "Too much load";
2140 return false;
2141 }
2142
2143 return true;
2144}
2145
2147ApplicationImp::journal(std::string const& name)
2148{
2149 return logs_->journal(name);
2150}
2151
2152void
2153ApplicationImp::setMaxDisallowedLedger()
2154{
2155 auto seq = getRelationalDatabase().getMaxLedgerSeq();
2156 if (seq)
2157 maxDisallowedLedger_ = *seq;
2158
2159 JLOG(m_journal.trace())
2160 << "Max persisted ledger is " << maxDisallowedLedger_;
2161}
2162
2163//------------------------------------------------------------------------------
2164
2165Application::Application() : beast::PropertyStream::Source("app")
2166{
2167}
2168
2169//------------------------------------------------------------------------------
2170
2175 std::unique_ptr<TimeKeeper> timeKeeper)
2176{
2178 std::move(config), std::move(logs), std::move(timeKeeper));
2179}
2180
2181void
2182fixConfigPorts(Config& config, Endpoints const& endpoints)
2183{
2184 for (auto const& [name, ep] : endpoints)
2185 {
2186 if (!config.exists(name))
2187 continue;
2188
2189 auto& section = config[name];
2190 auto const optPort = section.get("port");
2191 if (optPort)
2192 {
2193 std::uint16_t const port =
2194 beast::lexicalCast<std::uint16_t>(*optPort);
2195 if (!port)
2196 section.set("port", std::to_string(ep.port()));
2197 }
2198 }
2199}
2200
2201} // namespace xrpl
boost::asio::io_context & get_io_context()
Definition BasicApp.h:25
Unserialize a JSON document into a Value.
Definition json_reader.h:18
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Represents a JSON value.
Definition json_value.h:131
bool isObjectOrNull() const
Value removeMember(char const *key)
Remove and return the named member.
std::string asString() const
Returns the unquoted string value.
A generic endpoint for log messages.
Definition Journal.h:41
Stream fatal() const
Definition Journal.h:333
Stream warn() const
Definition Journal.h:321
std::string const & name() const
Returns the name of this source.
void add(Source &source)
Add a child source.
Abstract stream with RAII containers that produce a property tree.
A metric for reporting event timing.
Definition Event.h:22
void notify(std::chrono::duration< Rep, Period > const &value) const
Push an event notification.
Definition Event.h:45
Measures handler latency on an io_context queue.
void sample(Handler &&handler)
Initiate continuous i/o latency sampling.
void cancel()
Cancel all pending i/o.
The amendment table stores the list of enabled and potential amendments.
beast::io_latency_probe< std::chrono::steady_clock > m_probe
void operator()(Duration const &elapsed)
std::atomic< std::chrono::milliseconds > lastSample_
io_latency_sampler(beast::insight::Event ev, beast::Journal journal, std::chrono::milliseconds interval, boost::asio::io_context &ios)
std::chrono::milliseconds get() const
LedgerReplayer & getLedgerReplayer() override
Application::MutexType & getMasterMutex() override
std::optional< std::pair< PublicKey, SecretKey > > nodeIdentity_
InboundLedgers & getInboundLedgers() override
std::unique_ptr< LedgerCleaner > ledgerCleaner_
std::unique_ptr< LoadManager > m_loadManager
void start(bool withTimers) override
LoadFeeTrack & getFeeTrack() override
Cluster & cluster() override
std::unique_ptr< perf::PerfLog > perfLog_
std::unique_ptr< HashRouter > hashRouter_
std::optional< OpenLedger > openLedger_
RCLValidations & getValidations() override
void run() override
OpenLedger & openLedger() override
Resource::Manager & getResourceManager() override
NodeStoreScheduler m_nodeStoreScheduler
ClosureCounter< void, boost::system::error_code const & > waitHandlerCounter_
beast::Journal m_journal
RelationalDatabase & getRelationalDatabase() override
TransactionMaster & getMasterTransaction() override
std::chrono::milliseconds getIOLatency() override
std::unique_ptr< CollectorManager > m_collectorManager
boost::asio::io_context & getIOContext() override
std::optional< PublicKey const > getValidationPublicKey() const override
HashRouter & getHashRouter() override
LoadManager & getLoadManager() override
PendingSaves pendingSaves_
std::unique_ptr< RelationalDatabase > mRelationalDatabase
std::atomic< bool > checkSigs_
bool checkSigs() const override
bool serverOkay(std::string &reason) override
std::unique_ptr< SHAMapStore > m_shaMapStore
Application::MutexType m_masterMutex
InboundTransactions & getInboundTransactions() override
io_latency_sampler m_io_latency_sampler
std::unique_ptr< AmendmentTable > m_amendmentTable
std::unique_ptr< InboundTransactions > m_inboundTransactions
SHAMapStore & getSHAMapStore() override
boost::asio::steady_timer sweepTimer_
std::unique_ptr< NodeStore::Database > m_nodeStore
std::unique_ptr< LoadFeeTrack > mFeeTrack
boost::asio::steady_timer entropyTimer_
std::unique_ptr< Overlay > overlay_
bool setup(boost::program_options::variables_map const &cmdline) override
Overlay & overlay() override
std::unique_ptr< Config > config_
ManifestCache & publisherManifests() override
std::unique_ptr< ManifestCache > validatorManifests_
CollectorManager & getCollectorManager() override
std::optional< uint256 > trapTxID_
std::unique_ptr< ResolverAsio > m_resolver
NetworkOPs & getOPs() override
TimeKeeper & timeKeeper() override
std::unique_ptr< ValidatorList > validators_
std::unique_ptr< TxQ > txQ_
static std::size_t numberOfThreads(Config const &config)
OpenLedger const & openLedger() const override
std::unique_ptr< ManifestCache > publisherManifests_
LedgerIndex getMaxDisallowedLedger() override
Ensure that a newly-started validator does not sign proposals older than the last ledger it persisted...
NodeCache & getTempNodeCache() override
Logs & logs() override
OrderBookDB m_orderBookDB
ValidatorList & validators() override
PeerReservationTable & peerReservations() override
ApplicationImp(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
std::unique_ptr< PeerReservationTable > peerReservations_
std::unique_ptr< Resource::Manager > m_resourceManager
std::pair< PublicKey, SecretKey > const & nodeIdentity() override
std::unique_ptr< Logs > logs_
std::unique_ptr< DatabaseCon > mWalletDB
CachedSLEs & cachedSLEs() override
ValidatorSite & validatorSites() override
virtual std::optional< uint256 > const & trapTxID() const override
std::atomic_flag isTimeToStop
std::unique_ptr< LedgerMaster > m_ledgerMaster
std::unique_ptr< GRPCServer > grpcServer_
std::unique_ptr< ServerHandler > serverHandler_
ValidatorKeys const validatorKeys_
std::uint64_t instanceID() const override
Returns a 64-bit instance identifier, generated at startup.
OrderBookDB & getOrderBookDB() override
Family & getNodeFamily() override
void gotTXSet(std::shared_ptr< SHAMap > const &set, bool fromAcquire)
Config & config() override
DatabaseCon & getWalletDB() override
Retrieve the "wallet database".
PathRequests & getPathRequests() override
bool isStopping() const override
std::unique_ptr< TimeKeeper > timeKeeper_
beast::Journal journal(std::string const &name) override
std::unique_ptr< ValidatorSite > validatorSites_
RCLValidations mValidations
void signalStop(std::string msg) override
std::uint64_t const instanceCookie_
LedgerCleaner & getLedgerCleaner() override
ManifestCache & validatorManifests() override
AmendmentTable & getAmendmentTable() override
int fdRequired() const override
TaggedCache< uint256, AcceptedLedger > m_acceptedLedgerCache
std::unique_ptr< PathRequests > m_pathRequests
std::unique_ptr< JobQueue > m_jobQueue
LedgerMaster & getLedgerMaster() override
NodeStore::Database & getNodeStore() override
TransactionMaster m_txMaster
std::unique_ptr< Cluster > cluster_
std::unique_ptr< NetworkOPs > m_networkOPs
virtual ServerHandler & getServerHandler() override
JobQueue & getJobQueue() override
PendingSaves & pendingSaves() override
void onWrite(beast::PropertyStream::Map &stream) override
Subclass override.
std::unique_ptr< InboundLedgers > m_inboundLedgers
TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache() override
perf::PerfLog & getPerfLog() override
TxQ & getTxQ() override
boost::asio::signal_set m_signals
std::unique_ptr< LedgerReplayer > m_ledgerReplayer
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
The role of a ClosureCounter is to assist in shutdown by letting callers wait for the completion of c...
Provides the beast::insight::Collector service.
bool standalone() const
Definition Config.h:318
bool FORCE_MULTI_THREAD
Definition Config.h:221
std::size_t NODE_SIZE
Definition Config.h:195
int IO_WORKERS
Definition Config.h:217
int WORKERS
Definition Config.h:216
Routing table for objects identified by hash.
Definition HashRouter.h:78
Manages the lifetime of inbound ledgers.
Manages the acquisition and lifetime of transaction sets.
A pool of threads to perform work.
Definition JobQueue.h:38
Check the ledger/transaction databases to make sure they have continuity.
Manages the lifetime of ledger replay tasks.
Manages the current fee schedule.
Manages load sources.
Definition LoadManager.h:27
Manages partitions for logging.
Definition Log.h:33
Remembers manifests with the highest sequence number.
Definition Manifest.h:237
Provides server functionality for clients.
Definition NetworkOPs.h:70
A NodeStore::Scheduler which uses the JobQueue.
Persistency layer for NodeObject.
Definition Database.h:32
Simple NodeStore Scheduler that just performs the tasks synchronously.
static Manager & instance()
Returns the instance of the manager singleton.
virtual std::unique_ptr< Database > make_Database(std::size_t burstSize, Scheduler &scheduler, int readThreads, Section const &backendParameters, beast::Journal journal)=0
Construct a NodeStore database.
Represents the open ledger.
Definition OpenLedger.h:33
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:46
void rawTxInsert(key_type const &key, std::shared_ptr< Serializer const > const &txn, std::shared_ptr< Serializer const > const &metaData) override
Add a transaction to the tx map.
Definition OpenView.cpp:240
Manages the set of connected peers.
Definition Overlay.h:30
Keeps track of which ledgers haven't been fully saved.
A public key.
Definition PublicKey.h:43
static std::unique_ptr< RelationalDatabase > init(Application &app, Config const &config, JobQueue &jobQueue)
init Creates and returns an appropriate RelationalDatabase instance based on configuration.
static std::unique_ptr< ResolverAsio > New(boost::asio::io_context &, beast::Journal)
A consumption charge.
Definition Charge.h:11
An endpoint that consumes resources.
Definition Consumer.h:17
Tracks load and resource consumption.
class to create database, launch online delete thread, and related SQLite database
Definition SHAMapStore.h:19
Holds the serialized result of parsing an input JSON object.
std::optional< STObject > object
The STObject if the parse was successful.
Holds a collection of configuration values.
Definition BasicConfig.h:26
std::size_t size() const
Returns the number of items in the container.
Manages various times used by the server.
Definition TimeKeeper.h:13
Transaction Queue.
Definition TxQ.h:42
Validator keys and manifest as set in configuration file.
std::optional< Keys > keys
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:484
bool isZero() const
Definition base_uint.h:521
Singleton class that maintains performance counters and optionally writes Json-formatted data to a di...
Definition PerfLog.h:32
T empty(T... args)
T endl(T... args)
T hardware_concurrency(T... args)
T is_same_v
T load(T... args)
T make_unique(T... args)
T max(T... args)
T min(T... args)
unsigned int UInt
A namespace for easy access to logging severity values.
Definition Journal.h:11
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
STL namespace.
std::unique_ptr< Manager > make_Manager(beast::insight::Collector::ptr const &collector, beast::Journal journal)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::shared_ptr< Ledger > loadByHash(uint256 const &ledgerHash, Application &app, bool acquire)
Definition Ledger.cpp:1115
std::pair< PublicKey, SecretKey > getNodeIdentity(Application &app, boost::program_options::variables_map const &cmdline)
The cryptographic credentials identifying this server instance.
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
csprng_engine & crypto_prng()
The default cryptographically secure PRNG.
std::unique_ptr< LedgerCleaner > make_LedgerCleaner(Application &app, beast::Journal journal)
std::unique_ptr< LoadManager > make_LoadManager(Application &app, beast::Journal journal)
Stopwatch & stopwatch()
Returns an instance of a wall clock.
Definition chrono.h:100
TxQ::Setup setup_TxQ(Config const &config)
Build a TxQ::Setup object from application configuration.
Definition TxQ.cpp:1893
std::tuple< std::shared_ptr< Ledger >, std::uint32_t, uint256 > getLatestLedger(Application &app)
Definition Ledger.cpp:1092
create_genesis_t const create_genesis
Definition Ledger.cpp:32
std::unique_ptr< NetworkOPs > make_NetworkOPs(Application &app, NetworkOPs::clock_type &clock, bool standalone, std::size_t minPeerCount, bool startvalid, JobQueue &job_queue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_context &io_svc, beast::Journal journal, beast::insight::Collector::ptr const &collector)
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
std::unique_ptr< SHAMapStore > make_SHAMapStore(Application &app, NodeStore::Scheduler &scheduler, beast::Journal journal)
std::unique_ptr< AmendmentTable > make_AmendmentTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
std::unique_ptr< PeerSet > make_DummyPeerSet(Application &app)
Make a dummy PeerSet that does not do anything.
Definition PeerSet.cpp:169
@ hotACCOUNT_NODE
Definition NodeObject.h:16
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
ServerHandler::Setup setup_ServerHandler(Config const &config, std::ostream &&log)
std::shared_ptr< Ledger > loadByIndex(std::uint32_t ledgerIndex, Application &app, bool acquire)
Definition Ledger.cpp:1102
std::unique_ptr< CollectorManager > make_CollectorManager(Section const &params, beast::Journal journal)
std::unique_ptr< DatabaseCon > makeWalletDB(DatabaseCon::Setup const &setup, beast::Journal j)
makeWalletDB Opens the wallet database and returns it.
Definition Wallet.cpp:8
std::unique_ptr< InboundLedgers > make_InboundLedgers(Application &app, InboundLedgers::clock_type &clock, beast::insight::Collector::ptr const &collector)
std::unique_ptr< ServerHandler > make_ServerHandler(Application &app, boost::asio::io_context &io_context, JobQueue &jobQueue, NetworkOPs &networkOPs, Resource::Manager &resourceManager, CollectorManager &cm)
constexpr auto megabytes(T value) noexcept
static void fixConfigPorts(Config &config, Endpoints const &endpoints)
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
void initAccountIdCache(std::size_t count)
Initialize the global cache used to map AccountID to base58 conversions.
Definition AccountID.cpp:88
std::unique_ptr< InboundTransactions > make_InboundTransactions(Application &app, beast::insight::Collector::ptr const &collector, std::function< void(std::shared_ptr< SHAMap > const &, bool)> gotSet)
void addJson(Json::Value &json, LedgerFill const &fill)
Given a Ledger and options, fill a Json::Value with a description of the ledger.
Overlay::Setup setup_Overlay(BasicConfig const &config)
HashRouter::Setup setup_HashRouter(Config const &config)
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
Definition apply.cpp:100
std::unordered_map< std::string, boost::asio::ip::tcp::endpoint > Endpoints
Definition ServerImpl.h:22
std::optional< uint256 > getRegisteredFeature(std::string const &name)
Definition Feature.cpp:363
std::unique_ptr< PeerSetBuilder > make_PeerSetBuilder(Application &app)
Definition PeerSet.cpp:126
std::unique_ptr< Overlay > make_Overlay(Application &app, Overlay::Setup const &setup, ServerHandler &serverHandler, Resource::Manager &resourceManager, Resolver &resolver, boost::asio::io_context &io_context, BasicConfig const &config, beast::insight::Collector::ptr const &collector)
Creates the implementation of Overlay.
T ref(T... args)
T length(T... args)
T strlen(T... args)
static std::string importNodeDatabase()
T to_string(T... args)
T what(T... args)