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