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