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