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