1#include <xrpld/app/consensus/RCLValidations.h>
2#include <xrpld/app/ledger/InboundLedgers.h>
3#include <xrpld/app/ledger/InboundTransactions.h>
4#include <xrpld/app/ledger/LedgerCleaner.h>
5#include <xrpld/app/ledger/LedgerMaster.h>
6#include <xrpld/app/ledger/LedgerPersistence.h>
7#include <xrpld/app/ledger/LedgerReplayer.h>
8#include <xrpld/app/ledger/LedgerToJson.h>
9#include <xrpld/app/ledger/OpenLedger.h>
10#include <xrpld/app/ledger/OrderBookDBImpl.h>
11#include <xrpld/app/ledger/TransactionMaster.h>
12#include <xrpld/app/main/Application.h>
13#include <xrpld/app/main/BasicApp.h>
14#include <xrpld/app/main/GRPCServer.h>
15#include <xrpld/app/main/LoadManager.h>
16#include <xrpld/app/main/NodeIdentity.h>
17#include <xrpld/app/main/NodeStoreScheduler.h>
18#include <xrpld/app/misc/SHAMapStore.h>
19#include <xrpld/app/misc/TxQ.h>
20#include <xrpld/app/misc/ValidatorKeys.h>
21#include <xrpld/app/misc/ValidatorSite.h>
22#include <xrpld/app/misc/make_NetworkOPs.h>
23#include <xrpld/app/misc/setup_HashRouter.h>
24#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
25#include <xrpld/core/ConfigSections.h>
26#include <xrpld/core/NetworkIDServiceImpl.h>
27#include <xrpld/overlay/Cluster.h>
28#include <xrpld/overlay/PeerSet.h>
29#include <xrpld/overlay/make_Overlay.h>
30#include <xrpld/rpc/detail/PathRequestManager.h>
31#include <xrpld/shamap/NodeFamily.h>
33#include <xrpl/basics/ByteUtilities.h>
34#include <xrpl/basics/MallocTrim.h>
35#include <xrpl/basics/ResolverAsio.h>
36#include <xrpl/basics/random.h>
37#include <xrpl/beast/asio/io_latency_probe.h>
38#include <xrpl/beast/core/LexicalCast.h>
39#include <xrpl/core/HashRouter.h>
40#include <xrpl/core/PeerReservationTable.h>
41#include <xrpl/core/PerfLog.h>
42#include <xrpl/crypto/csprng.h>
43#include <xrpl/json/json_reader.h>
44#include <xrpl/ledger/AmendmentTable.h>
45#include <xrpl/ledger/PendingSaves.h>
46#include <xrpl/nodestore/DummyScheduler.h>
47#include <xrpl/protocol/ApiVersion.h>
48#include <xrpl/protocol/BuildInfo.h>
49#include <xrpl/protocol/Feature.h>
50#include <xrpl/protocol/Protocol.h>
51#include <xrpl/protocol/STParsedJSON.h>
52#include <xrpl/rdb/DatabaseCon.h>
53#include <xrpl/resource/Fees.h>
54#include <xrpl/server/LoadFeeTrack.h>
55#include <xrpl/server/Wallet.h>
56#include <xrpl/tx/apply.h>
58#include <boost/algorithm/string/predicate.hpp>
59#include <boost/asio/steady_timer.hpp>
60#include <boost/system/error_code.hpp>
95 boost::asio::io_context& ios)
106 template <
class Duration>
111 auto const lastSample = ceil<milliseconds>(elapsed);
115 if (lastSample >= 10ms)
117 if (lastSample >= 500ms)
119 JLOG(
m_journal.
warn()) <<
"io_context latency = " << lastSample.count();
221#if XRPL_SINGLE_IO_SERVICE_THREAD
257 perf::setup_PerfLog(
config_->section(
"perf"),
config_->CONFIG_DIR),
259 logs_->journal(
"PerfLog"),
297 logs_->journal(
"JobQueue"),
311 logs_->journal(
"TaggedCache"))
318 logs_->journal(
"CachedSLEs"))
337 logs_->journal(
"PathRequest"),
345 logs_->journal(
"LedgerMaster")))
358 gotTXSet(set, fromAcquire);
372 logs_->journal(
"TaggedCache"))
384 logs_->journal(
"NetworkOPs"),
401 config_->legacy(
"database_path"),
402 logs_->journal(
"ValidatorList"),
437 logs_->journal(
"Application"),
467 setup(boost::program_options::variables_map
const& cmdline)
override;
469 start(
bool withTimers)
override;
533 LogicError(
"Accessing Application::nodeIdentity() before it is initialized.");
556 "xrpl::ApplicationImp::getServerHandler : non-null server "
561 boost::asio::io_context&
769 XRPL_ASSERT(
overlay_,
"xrpl::ApplicationImp::overlay : non-null overlay");
776 XRPL_ASSERT(
txQ_,
"xrpl::ApplicationImp::getTxQ : non-null transaction queue");
785 "xrpl::ApplicationImp::getRelationalDatabase : non-null relational database");
792 XRPL_ASSERT(
mWalletDB,
"xrpl::ApplicationImp::getWalletDB : non-null wallet database");
809 "xrpl::ApplicationImp::initRelationalDatabase : null wallet "
818 setup.useGlobalPragma =
false;
836 auto j =
logs_->journal(
"NodeObject");
846 JLOG(j.warn()) <<
"Starting node import from '" << source->getName() <<
"' to '"
850 auto const start = steady_clock::now();
854 auto const elapsed = duration_cast<seconds>(steady_clock::now() -
start);
855 JLOG(j.warn()) <<
"Node import from '" << source->getName() <<
"' took "
856 << elapsed.count() <<
" seconds.";
878 if (
auto optionalCountedHandler =
880 if (e.value() == boost::system::errc::success)
882 m_jobQueue->addJob(jtSWEEP,
"sweep", [this]() { doSweep(); });
885 if (e.value() != boost::system::errc::success &&
886 e.value() != boost::asio::error::operation_aborted)
889 JLOG(m_journal.error())
890 <<
"Sweep timer got error '" << e.message() <<
"'. Restarting timer.";
899 sweepTimer_.async_wait(std::move(*optionalCountedHandler));
907 if (
auto optionalCountedHandler =
908 waitHandlerCounter_.wrap([
this](boost::system::error_code
const& e) {
909 if (e.value() == boost::system::errc::success)
911 crypto_prng().mix_entropy();
915 if (e.value() != boost::system::errc::success &&
916 e.value() != boost::asio::error::operation_aborted)
919 JLOG(m_journal.error()) <<
"Entropy timer got error '" << e.message()
920 <<
"'. Restarting timer.";
925 using namespace std::chrono_literals;
926 entropyTimer_.expires_after(5min);
927 entropyTimer_.async_wait(std::move(*optionalCountedHandler));
935 relationalDatabase_,
"xrpl::ApplicationImp::doSweep : non-null relational database");
936 if (!config_->standalone() && !relationalDatabase_->transactionDbHasSpace(*config_))
938 signalStop(
"Out of transaction DB space");
947 nodeFamily_.getFullBelowCache();
950 nodeFamily_.getTreeNodeCache();
952 std::size_t const oldFullBelowSize = fullBelowCache->size();
953 std::size_t const oldTreeNodeSize = treeNodeCache->size();
957 JLOG(m_journal.debug())
958 <<
"NodeFamily::FullBelowCache sweep. Size before: " << oldFullBelowSize
959 <<
"; size after: " << fullBelowCache->size();
961 JLOG(m_journal.debug())
962 <<
"NodeFamily::TreeNodeCache sweep. Size before: " << oldTreeNodeSize
963 <<
"; size after: " << treeNodeCache->size();
967 getMasterTransaction().getCache();
971 getMasterTransaction().sweep();
973 JLOG(m_journal.debug()) <<
"MasterTransaction sweep. Size before: " << oldMasterTxSize
974 <<
"; size after: " << masterTxCache.
size();
977 std::size_t const oldLedgerMasterCacheSize = getLedgerMaster().getFetchPackCacheSize();
979 getLedgerMaster().sweep();
981 JLOG(m_journal.debug())
982 <<
"LedgerMaster sweep. Size before: " << oldLedgerMasterCacheSize
983 <<
"; size after: " << getLedgerMaster().getFetchPackCacheSize();
987 std::size_t const oldTempNodeCacheSize = getTempNodeCache().size();
989 getTempNodeCache().sweep();
991 JLOG(m_journal.debug()) <<
"TempNodeCache sweep. Size before: " << oldTempNodeCacheSize
992 <<
"; size after: " << getTempNodeCache().size();
995 std::size_t const oldCurrentCacheSize = getValidations().sizeOfCurrentCache();
996 std::size_t const oldSizeSeqEnforcesSize = getValidations().sizeOfSeqEnforcersCache();
997 std::size_t const oldByLedgerSize = getValidations().sizeOfByLedgerCache();
998 std::size_t const oldBySequenceSize = getValidations().sizeOfBySequenceCache();
1000 getValidations().expire(m_journal);
1002 JLOG(m_journal.debug())
1003 <<
"Validations Current expire. Size before: " << oldCurrentCacheSize
1004 <<
"; size after: " << getValidations().sizeOfCurrentCache();
1006 JLOG(m_journal.debug())
1007 <<
"Validations SeqEnforcer expire. Size before: " << oldSizeSeqEnforcesSize
1008 <<
"; size after: " << getValidations().sizeOfSeqEnforcersCache();
1010 JLOG(m_journal.debug())
1011 <<
"Validations ByLedger expire. Size before: " << oldByLedgerSize
1012 <<
"; size after: " << getValidations().sizeOfByLedgerCache();
1014 JLOG(m_journal.debug())
1015 <<
"Validations BySequence expire. Size before: " << oldBySequenceSize
1016 <<
"; size after: " << getValidations().sizeOfBySequenceCache();
1019 std::size_t const oldInboundLedgersSize = getInboundLedgers().cacheSize();
1021 getInboundLedgers().sweep();
1023 JLOG(m_journal.debug())
1024 <<
"InboundLedgers sweep. Size before: " << oldInboundLedgersSize
1025 <<
"; size after: " << getInboundLedgers().cacheSize();
1028 size_t const oldTasksSize = getLedgerReplayer().tasksSize();
1029 size_t const oldDeltasSize = getLedgerReplayer().deltasSize();
1030 size_t const oldSkipListsSize = getLedgerReplayer().skipListsSize();
1032 getLedgerReplayer().sweep();
1034 JLOG(m_journal.debug()) <<
"LedgerReplayer tasks sweep. Size before: " << oldTasksSize
1035 <<
"; size after: " << getLedgerReplayer().tasksSize();
1037 JLOG(m_journal.debug())
1038 <<
"LedgerReplayer deltas sweep. Size before: " << oldDeltasSize
1039 <<
"; size after: " << getLedgerReplayer().deltasSize();
1041 JLOG(m_journal.debug())
1042 <<
"LedgerReplayer skipLists sweep. Size before: " << oldSkipListsSize
1043 <<
"; size after: " << getLedgerReplayer().skipListsSize();
1046 std::size_t const oldAcceptedLedgerSize = m_acceptedLedgerCache.size();
1048 m_acceptedLedgerCache.sweep();
1050 JLOG(m_journal.debug())
1051 <<
"AcceptedLedgerCache sweep. Size before: " << oldAcceptedLedgerSize
1052 <<
"; size after: " << m_acceptedLedgerCache.size();
1055 std::size_t const oldCachedSLEsSize = cachedSLEs_.size();
1057 cachedSLEs_.sweep();
1059 JLOG(m_journal.debug()) <<
"CachedSLEs sweep. Size before: " << oldCachedSLEsSize
1060 <<
"; size after: " << cachedSLEs_.size();
1072 return maxDisallowedLedger_;
1084 return get_number_of_threads();
1093 startGenesisLedger();
1096 getLastFullLedger();
1109 setMaxDisallowedLedger();
1122ApplicationImp::setup(boost::program_options::variables_map
const& cmdline)
1132 m_signals.
add(SIGINT);
1133 m_signals.add(SIGTERM);
1134 m_signals.async_wait([
this](boost::system::error_code
const& ec,
int signum) {
1136 if (ec == boost::asio::error::operation_aborted)
1139 JLOG(m_journal.info()) <<
"Received signal " << signum;
1141 if (signum == SIGTERM || signum == SIGINT)
1142 signalStop(
"Signal: " + to_string(signum));
1145 auto debug_log = config_->getDebugLogFile();
1147 if (!debug_log.empty())
1152 if (!logs_->open(debug_log))
1153 std::cerr <<
"Can't open log file " << debug_log <<
'\n';
1156 if (logs_->threshold() > kDebug)
1157 logs_->threshold(kDebug);
1160 JLOG(m_journal.info()) <<
"Process starting: " << BuildInfo::getFullVersionString()
1161 <<
", Instance Cookie: " << instanceCookie_;
1163 if (numberOfThreads(*config_) < 2)
1165 JLOG(m_journal.warn()) <<
"Limited to a single I/O service thread by "
1166 "system configuration.";
1170 logs_->silent(config_->silent());
1172 if (!initRelationalDatabase() || !initNodeStore())
1175 if (!peerReservations_->load(getWalletDB()))
1177 JLOG(m_journal.fatal()) <<
"Cannot find peer reservations!";
1181 if (validatorKeys_.keys)
1182 setMaxDisallowedLedger();
1186 auto const supported = []() {
1187 auto const& amendments = detail::supportedAmendments();
1189 supported.reserve(amendments.size());
1190 for (
auto const& [a, vote] : amendments)
1193 XRPL_ASSERT(f,
"xrpl::ApplicationImp::setup : registered feature");
1195 supported.emplace_back(a, *f, vote);
1199 Section const& downVoted = config_->section(SECTION_VETO_AMENDMENTS);
1201 Section const& upVoted = config_->section(SECTION_AMENDMENTS);
1205 config().AMENDMENT_MAJORITY_TIME,
1209 logs_->journal(
"Amendments"));
1212 Pathfinder::initPathTable();
1214 auto const startUp = config_->START_UP;
1215 JLOG(m_journal.debug()) <<
"startUp: " << startUp;
1216 if (startUp == StartUpType::Fresh)
1218 JLOG(m_journal.info()) <<
"Starting new Ledger";
1220 startGenesisLedger();
1223 startUp == StartUpType::Load || startUp == StartUpType::LoadFile ||
1224 startUp == StartUpType::Replay)
1226 JLOG(m_journal.info()) <<
"Loading specified Ledger";
1229 config_->START_LEDGER,
1230 startUp == StartUpType::Replay,
1231 startUp == StartUpType::LoadFile,
1232 config_->TRAP_TX_HASH))
1234 JLOG(m_journal.error()) <<
"The specified ledger could not be loaded.";
1235 if (config_->FAST_LOAD)
1239 startGenesisLedger();
1247 else if (startUp == StartUpType::Network)
1251 if (!config_->standalone())
1252 m_networkOPs->setNeedNetworkLedger();
1254 startGenesisLedger();
1258 startGenesisLedger();
1261 if (
auto const& forcedRange = config().FORCED_LEDGER_RANGE_PRESENT)
1263 m_ledgerMaster->setLedgerRangePresent(forcedRange->first, forcedRange->second);
1266 m_orderBookDB->setup(getLedgerMaster().getCurrentLedger());
1270 if (!cluster_->load(config().section(SECTION_CLUSTER_NODES)))
1272 JLOG(m_journal.fatal()) <<
"Invalid entry in cluster configuration.";
1277 if (validatorKeys_.configInvalid())
1280 if (!validatorManifests_->load(
1282 "ValidatorManifests",
1283 validatorKeys_.manifest,
1284 config().section(SECTION_VALIDATOR_KEY_REVOCATION).values()))
1286 JLOG(m_journal.fatal()) <<
"Invalid configured validator manifest.";
1290 publisherManifests_->load(getWalletDB(),
"PublisherManifests");
1299 if (validatorKeys_.keys)
1300 localSigningKey = validatorKeys_.keys->publicKey;
1303 if (!validators_->load(
1305 config().section(SECTION_VALIDATORS).values(),
1306 config().section(SECTION_VALIDATOR_LIST_KEYS).values(),
1307 config().VALIDATOR_LIST_THRESHOLD))
1309 JLOG(m_journal.fatal()) <<
"Invalid entry in validator configuration.";
1314 if (!validatorSites_->load(config().section(SECTION_VALIDATOR_LIST_SITES).values()))
1316 JLOG(m_journal.fatal()) <<
"Invalid entry in [" << SECTION_VALIDATOR_LIST_SITES <<
"]";
1321 m_amendmentTable->trustChanged(validators_->getQuorumKeys().second);
1342 m_collectorManager->collector());
1346 if (!m_networkOPs->beginConsensus(m_ledgerMaster->getClosedLedger()->header().hash, {}))
1348 JLOG(m_journal.fatal()) <<
"Unable to start consensus";
1357 setup.makeContexts();
1358 serverHandler_->setup(setup, m_journal);
1363 if (
auto stream = m_journal.fatal())
1365 stream <<
"Unable to setup server handler";
1367 stream <<
": " << e.
what();
1374 if (!config_->standalone())
1378 if (config_->PEER_PRIVATE && config_->IPS_FIXED.empty())
1380 JLOG(m_journal.warn()) <<
"No outbound peer connections will be made";
1385 m_networkOPs->setStateTimer();
1389 JLOG(m_journal.warn()) <<
"Running in standalone mode";
1391 m_networkOPs->setStandAlone();
1394 if (config_->canSign())
1396 JLOG(m_journal.warn()) <<
"*** The server is configured to allow the "
1397 "'sign' and 'sign_for'";
1398 JLOG(m_journal.warn()) <<
"*** commands. These commands have security "
1399 "implications and have";
1400 JLOG(m_journal.warn()) <<
"*** been deprecated. They will be removed "
1401 "in a future release of";
1402 JLOG(m_journal.warn()) <<
"*** rippled.";
1403 JLOG(m_journal.warn()) <<
"*** If you do not use them to sign "
1404 "transactions please edit your";
1405 JLOG(m_journal.warn()) <<
"*** configuration file and remove the [enable_signing] stanza.";
1406 JLOG(m_journal.warn()) <<
"*** If you do use them to sign transactions "
1407 "please migrate to a";
1408 JLOG(m_journal.warn()) <<
"*** standalone signing solution as soon as possible.";
1414 for (
auto const& cmd : config_->section(SECTION_RPC_STARTUP).lines())
1419 if (!jrReader.
parse(cmd, jvCommand))
1421 JLOG(m_journal.fatal())
1422 <<
"Couldn't parse entry in [" << SECTION_RPC_STARTUP <<
"]: '" << cmd;
1425 if (!config_->quiet())
1427 JLOG(m_journal.fatal()) <<
"Startup RPC: " << jvCommand <<
std::endl;
1433 {getJournal(
"RPCHandler"),
1442 RPC::apiMaximumSupportedVersion},
1446 RPC::doCommand(context, jvResult);
1448 if (!config_->quiet())
1450 JLOG(m_journal.fatal()) <<
"Result: " << jvResult <<
std::endl;
1454 validatorSites_->start();
1460ApplicationImp::start(
bool withTimers)
1462 JLOG(m_journal.info()) <<
"Application starting. Version is " << BuildInfo::getVersionString();
1470 m_io_latency_sampler.start();
1471 m_resolver->start();
1472 m_loadManager->start();
1473 m_shaMapStore->start();
1477 if (grpcServer_->start())
1478 fixConfigPorts(*config_, {{SECTION_PORT_GRPC, grpcServer_->getEndpoint()}});
1480 ledgerCleaner_->start();
1485ApplicationImp::run()
1487 if (!config_->standalone())
1493 getLoadManager().activateStallDetector();
1498 JLOG(m_journal.debug()) <<
"Application stopping";
1500 m_io_latency_sampler.cancel_async();
1508 m_io_latency_sampler.cancel();
1510 m_resolver->stop_async();
1520 sweepTimer_.cancel();
1522 catch (boost::system::system_error
const& e)
1524 JLOG(m_journal.error()) <<
"Application: sweepTimer cancel error: " << e.what();
1529 entropyTimer_.cancel();
1531 catch (boost::system::system_error
const& e)
1533 JLOG(m_journal.error()) <<
"Application: entropyTimer cancel error: " << e.what();
1539 using namespace std::chrono_literals;
1541 waitHandlerCounter_.join(
"Application", 1s, m_journal);
1543 mValidations.flush();
1545 validatorSites_->stop();
1548 validatorManifests_->save(getWalletDB(),
"ValidatorManifests", [
this](
PublicKey const& pubKey) {
1549 return getValidators().listed(pubKey);
1552 publisherManifests_->save(getWalletDB(),
"PublisherManifests", [
this](
PublicKey const& pubKey) {
1553 return getValidators().trustedPublisher(pubKey);
1558 m_loadManager->stop();
1559 m_shaMapStore->stop();
1563 grpcServer_->stop();
1564 m_networkOPs->stop();
1565 serverHandler_->stop();
1566 m_ledgerReplayer->stop();
1567 m_inboundTransactions->stop();
1568 m_inboundLedgers->stop();
1569 ledgerCleaner_->stop();
1570 m_nodeStore->stop();
1573 JLOG(m_journal.info()) <<
"Done.";
1583 JLOG(m_journal.warn()) <<
"Server stopping";
1586 JLOG(m_journal.warn()) <<
"Server stopping: " << msg;
1588 isTimeToStop.notify_all();
1593ApplicationImp::checkSigs()
const
1599ApplicationImp::checkSigs(
bool check)
1605ApplicationImp::isStopping()
const
1611ApplicationImp::fdRequired()
const
1618 needed += 2 * overlay_->limit();
1622 needed +=
std::max(5, m_shaMapStore->fdRequired());
1626 for (
auto const& p : serverHandler_->setup().ports)
1636ApplicationImp::startGenesisLedger()
1639 ? m_amendmentTable->getDesired()
1644 Rules{config_->features},
1645 config_->FEES.toFees(),
1648 m_ledgerMaster->storeLedger(genesis);
1651 next->updateSkipList();
1653 next->header().seq < XRP_LEDGER_EARLIEST_FEES || next->read(keylet::fees()),
1654 "xrpl::ApplicationImp::startGenesisLedger : valid ledger fees");
1655 next->setImmutable();
1656 openLedger_.emplace(next, cachedSLEs_, logs_->journal(
"OpenLedger"));
1657 m_ledgerMaster->storeLedger(next);
1658 m_ledgerMaster->switchLCL(next);
1662ApplicationImp::getLastFullLedger()
1664 auto j = getJournal(
"Ledger");
1668 auto const [ledger, seq,
hash] =
1675 ledger->header().seq < XRP_LEDGER_EARLIEST_FEES || ledger->read(keylet::fees()),
1676 "xrpl::ApplicationImp::getLastFullLedger : valid ledger fees");
1677 ledger->setImmutable();
1679 if (getLedgerMaster().haveLedger(seq))
1680 ledger->setValidated();
1682 if (ledger->header().hash ==
hash)
1684 JLOG(j.trace()) <<
"Loaded ledger: " <<
hash;
1688 if (
auto stream = j.error())
1690 stream <<
"Failed on ledger";
1692 addJson(p, {*ledger,
nullptr, LedgerFill::full});
1700 JLOG(j.warn()) <<
"Ledger in database: " << mn.
what();
1714 JLOG(m_journal.fatal()) <<
"Unable to open file '" << name <<
"'";
1721 if (!reader.
parse(ledgerFile, jLedger))
1723 JLOG(m_journal.fatal()) <<
"Unable to parse ledger JSON";
1730 if (ledger.
get().isMember(
"result"))
1731 ledger = ledger.
get()[
"result"];
1733 if (ledger.
get().isMember(
"ledger"))
1734 ledger = ledger.
get()[
"ledger"];
1737 auto closeTime = getTimeKeeper().closeTime();
1738 using namespace std::chrono_literals;
1739 auto closeTimeResolution = 30s;
1740 bool closeTimeEstimated =
false;
1743 if (ledger.
get().isMember(
"accountState"))
1745 if (ledger.
get().isMember(jss::ledger_index))
1747 seq = ledger.
get()[jss::ledger_index].asUInt();
1750 if (ledger.
get().isMember(
"close_time"))
1753 using d = tp::duration;
1754 closeTime = tp{d{ledger.
get()[
"close_time"].asUInt()}};
1756 if (ledger.
get().isMember(
"close_time_resolution"))
1759 closeTimeResolution =
seconds{ledger.
get()[
"close_time_resolution"].asUInt()};
1761 if (ledger.
get().isMember(
"close_time_estimated"))
1763 closeTimeEstimated = ledger.
get()[
"close_time_estimated"].asBool();
1765 if (ledger.
get().isMember(
"total_coins"))
1768 beast::lexicalCastThrow<std::uint64_t>(ledger.
get()[
"total_coins"].asString());
1771 ledger = ledger.
get()[
"accountState"];
1774 if (!ledger.
get().isArrayOrNull())
1776 JLOG(m_journal.fatal()) <<
"State nodes must be an array";
1781 seq, closeTime,
Rules{config_->features}, config_->FEES.toFees(), nodeFamily_);
1782 loadLedger->setTotalDrops(totalDrops);
1784 for (
Json::UInt index = 0; index < ledger.
get().size(); ++index)
1790 JLOG(m_journal.fatal()) <<
"Invalid entry in ledger";
1798 JLOG(m_journal.fatal()) <<
"Invalid entry in ledger";
1808 JLOG(m_journal.fatal()) <<
"Invalid entry in ledger";
1816 if (!loadLedger->addSLE(sle))
1818 JLOG(m_journal.fatal()) <<
"Couldn't add serialized ledger: " << uIndex;
1826 loadLedger->header().seq < XRP_LEDGER_EARLIEST_FEES || loadLedger->read(keylet::fees()),
1827 "xrpl::ApplicationImp::loadLedgerFromFile : valid ledger fees");
1828 loadLedger->setAccepted(closeTime, closeTimeResolution, !closeTimeEstimated);
1834 JLOG(m_journal.fatal()) <<
"Ledger contains invalid data: " << x.
what();
1840ApplicationImp::loadOldLedger(
1852 if (!ledgerID.
empty())
1853 loadLedger = loadLedgerFromFile(ledgerID);
1855 else if (ledgerID.
length() == 64)
1859 if (
hash.parseHex(ledgerID))
1871 InboundLedger::Reason::GENERIC,
1874 if (il->checkLocal())
1875 loadLedger = il->getLedger();
1879 else if (ledgerID.
empty() || boost::iequals(ledgerID,
"latest"))
1881 loadLedger = getLastFullLedger();
1891 loadByIndex(index,
Rules{config_->features}, config_->FEES.toFees(), *
this);
1903 replayLedger = loadLedger;
1905 JLOG(m_journal.info()) <<
"Loading parent ledger";
1908 replayLedger->header().parentHash,
1909 Rules{config_->features},
1910 config_->FEES.toFees(),
1914 JLOG(m_journal.info()) <<
"Loading parent ledger from node store";
1919 replayLedger->header().parentHash,
1921 InboundLedger::Reason::GENERIC,
1925 if (il->checkLocal())
1926 loadLedger = il->getLedger();
1931 JLOG(m_journal.fatal()) <<
"Replay ledger missing/damaged";
1933 "xrpl::ApplicationImp::loadOldLedger : replay ledger "
1940 using namespace std::chrono_literals;
1941 using namespace date;
1944 if (loadLedger->header().closeTime < ledgerWarnTimePoint)
1946 JLOG(m_journal.fatal()) <<
"\n\n*** WARNING ***\n"
1947 "You are replaying a ledger from before "
1948 << to_string(ledgerWarnTimePoint)
1950 "This replay will not handle your ledger as it was "
1952 "handled.\nConsider running an earlier version of rippled "
1954 "get the older rules.\n*** CONTINUING ***\n";
1957 JLOG(m_journal.info()) <<
"Loading ledger " << loadLedger->header().hash
1958 <<
" seq:" << loadLedger->header().seq;
1960 if (loadLedger->header().accountHash.isZero())
1963 JLOG(m_journal.fatal()) <<
"Ledger is empty.";
1964 UNREACHABLE(
"xrpl::ApplicationImp::loadOldLedger : ledger is empty");
1969 if (!loadLedger->walkLedger(getJournal(
"Ledger"),
true))
1972 JLOG(m_journal.fatal()) <<
"Ledger is missing nodes.";
1974 "xrpl::ApplicationImp::loadOldLedger : ledger is missing "
1980 if (!loadLedger->isSensible())
1984 j[jss::accountTreeHash] = to_string(loadLedger->header().accountHash);
1985 j[jss::transTreeHash] = to_string(loadLedger->header().txHash);
1986 JLOG(m_journal.fatal()) <<
"Ledger is not sensible: " << j;
1988 "xrpl::ApplicationImp::loadOldLedger : ledger is not "
1994 m_ledgerMaster->setLedgerRangePresent(loadLedger->header().seq, loadLedger->header().seq);
1996 m_ledgerMaster->switchLCL(loadLedger);
1997 loadLedger->setValidated();
1998 m_ledgerMaster->setFullLedger(loadLedger,
true,
false);
1999 openLedger_.emplace(loadLedger, cachedSLEs_, logs_->journal(
"OpenLedger"));
2007 for (
auto const& [_, tx] : replayData->orderedTxns())
2010 auto txID = tx->getTransactionID();
2011 if (trapTxID == txID)
2014 JLOG(m_journal.debug()) <<
"Trap transaction set: " << txID;
2020 forceValidity(getHashRouter(), txID, Validity::SigGoodOnly);
2028 m_ledgerMaster->takeReplay(std::move(replayData));
2030 if (trapTxID && !trapTxID_)
2032 JLOG(m_journal.fatal()) <<
"Ledger " << replayLedger->header().seq
2033 <<
" does not contain the transaction hash " << *trapTxID;
2040 JLOG(m_journal.fatal()) <<
"While loading specified ledger: " << mn.
what();
2043 catch (boost::bad_lexical_cast&)
2045 JLOG(m_journal.fatal()) <<
"Ledger specified '" << ledgerID <<
"' is not valid";
2055 if (!config().ELB_SUPPORT)
2060 reason =
"Server is shutting down";
2064 if (getOPs().isNeedNetworkLedger())
2066 reason =
"Not synchronized with network yet";
2070 if (getOPs().isAmendmentBlocked())
2072 reason =
"Server version too old";
2076 if (getOPs().isUNLBlocked())
2078 reason =
"No valid validator list available";
2082 if (getOPs().getOperatingMode() < OperatingMode::SYNCING)
2084 reason =
"Not synchronized with network";
2088 if (!getLedgerMaster().isCaughtUp(reason))
2091 if (getFeeTrack().isLoadedLocal())
2093 reason =
"Too much load";
2103 return logs_->journal(name);
2107ApplicationImp::setMaxDisallowedLedger()
2109 auto seq = getRelationalDatabase().getMaxLedgerSeq();
2111 maxDisallowedLedger_ = *seq;
2113 JLOG(m_journal.trace()) <<
"Max persisted ledger is " << maxDisallowedLedger_;
2131 std::move(config), std::move(logs), std::move(timeKeeper));
2137 for (
auto const& [name, ep] : endpoints)
2139 if (!config.
exists(name))
2142 auto& section = config[name];
2143 auto const optPort = section.get(
"port");
2146 std::uint16_t const port = beast::lexicalCast<std::uint16_t>(*optPort);
boost::asio::io_context & get_io_context()
Unserialize a JSON document into a Value.
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
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.
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.
void notify(std::chrono::duration< Rep, Period > const &value) const
Push an event notification.
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::insight::Event m_event
beast::io_latency_probe< std::chrono::steady_clock > m_probe
void operator()(Duration const &elapsed)
std::atomic< std::chrono::milliseconds > lastSample_
io_latency_sampler(beast::insight::Event ev, beast::Journal journal, std::chrono::milliseconds interval, boost::asio::io_context &ios)
std::chrono::milliseconds get() const
LedgerReplayer & getLedgerReplayer() override
Application::MutexType & getMasterMutex() override
std::optional< std::pair< PublicKey, SecretKey > > nodeIdentity_
InboundLedgers & getInboundLedgers() override
ValidatorList & getValidators() override
TimeKeeper & getTimeKeeper() override
NodeCache m_tempNodeCache
std::unique_ptr< LedgerCleaner > ledgerCleaner_
std::unique_ptr< LoadManager > m_loadManager
void start(bool withTimers) override
LoadFeeTrack & getFeeTrack() override
std::unique_ptr< PathRequestManager > m_pathRequestManager
std::unique_ptr< perf::PerfLog > perfLog_
std::unique_ptr< HashRouter > hashRouter_
std::optional< OpenLedger > openLedger_
RCLValidations & getValidations() override
Resource::Manager & getResourceManager() override
NodeStoreScheduler m_nodeStoreScheduler
ClosureCounter< void, boost::system::error_code const & > waitHandlerCounter_
RelationalDatabase & getRelationalDatabase() override
OpenLedger & getOpenLedger() override
TransactionMaster & getMasterTransaction() override
std::chrono::milliseconds getIOLatency() override
std::unique_ptr< CollectorManager > m_collectorManager
boost::asio::io_context & getIOContext() override
std::optional< PublicKey const > getValidationPublicKey() const override
HashRouter & getHashRouter() override
LoadManager & getLoadManager() override
size_t getNumberOfThreads() const override
Returns the number of io_context (I/O worker) threads used by the application.
PendingSaves pendingSaves_
ManifestCache & getValidatorManifests() override
std::atomic< bool > checkSigs_
bool checkSigs() const override
ManifestCache & getPublisherManifests() override
bool serverOkay(std::string &reason) override
std::unique_ptr< SHAMapStore > m_shaMapStore
Application::MutexType m_masterMutex
InboundTransactions & getInboundTransactions() override
io_latency_sampler m_io_latency_sampler
std::unique_ptr< AmendmentTable > m_amendmentTable
std::unique_ptr< InboundTransactions > m_inboundTransactions
SHAMapStore & getSHAMapStore() override
boost::asio::steady_timer sweepTimer_
std::unique_ptr< NodeStore::Database > m_nodeStore
std::unique_ptr< LoadFeeTrack > mFeeTrack
boost::asio::steady_timer entropyTimer_
std::unique_ptr< Overlay > overlay_
bool setup(boost::program_options::variables_map const &cmdline) override
bool initRelationalDatabase()
std::unique_ptr< Config > config_
std::unique_ptr< ManifestCache > validatorManifests_
CollectorManager & getCollectorManager() override
std::optional< uint256 > trapTxID_
std::unique_ptr< ResolverAsio > m_resolver
NetworkOPs & getOPs() override
std::unique_ptr< ValidatorList > validators_
std::unique_ptr< TxQ > txQ_
static std::size_t numberOfThreads(Config const &config)
std::unique_ptr< ManifestCache > publisherManifests_
CachedSLEs & getCachedSLEs() override
LedgerIndex getMaxDisallowedLedger() override
Ensure that a newly-started validator does not sign proposals older than the last ledger it persisted...
NodeCache & getTempNodeCache() override
ApplicationImp(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
std::unique_ptr< PeerReservationTable > peerReservations_
std::unique_ptr< Resource::Manager > m_resourceManager
Cluster & getCluster() override
std::pair< PublicKey, SecretKey > const & nodeIdentity() override
std::unique_ptr< Logs > logs_
std::unique_ptr< DatabaseCon > mWalletDB
NetworkIDService & getNetworkIDService() override
std::atomic_flag isTimeToStop
std::optional< SQLiteDatabase > relationalDatabase_
OpenLedger const & getOpenLedger() const override
std::unique_ptr< LedgerMaster > m_ledgerMaster
std::unique_ptr< GRPCServer > grpcServer_
std::unique_ptr< ServerHandler > serverHandler_
Application & getApp() override
ValidatorKeys const validatorKeys_
std::uint64_t instanceID() const override
Returns a 64-bit instance identifier, generated at startup.
OrderBookDB & getOrderBookDB() override
Family & getNodeFamily() override
PeerReservationTable & getPeerReservations() override
Config & config() override
DatabaseCon & getWalletDB() override
Retrieve the "wallet database".
bool isStopping() const override
std::unique_ptr< TimeKeeper > timeKeeper_
void gotTXSet(std::shared_ptr< SHAMap > const &set, bool fromAcquire) const
virtual std::optional< uint256 > const & getTrapTxID() const override
std::unique_ptr< ValidatorSite > validatorSites_
Logs & getLogs() override
RCLValidations mValidations
PathRequestManager & getPathRequestManager() override
void signalStop(std::string msg) override
std::uint64_t const instanceCookie_
LedgerCleaner & getLedgerCleaner() override
AmendmentTable & getAmendmentTable() override
int fdRequired() const override
beast::Journal getJournal(std::string const &name) override
TaggedCache< uint256, AcceptedLedger > m_acceptedLedgerCache
bool initNodeStore() const
std::unique_ptr< JobQueue > m_jobQueue
LedgerMaster & getLedgerMaster() override
NodeStore::Database & getNodeStore() override
std::unique_ptr< OrderBookDB > m_orderBookDB
TransactionMaster m_txMaster
ValidatorSite & getValidatorSites() override
std::unique_ptr< Cluster > cluster_
PendingSaves & getPendingSaves() override
std::unique_ptr< NetworkOPs > m_networkOPs
Overlay & getOverlay() override
virtual ServerHandler & getServerHandler() override
JobQueue & getJobQueue() override
void onWrite(beast::PropertyStream::Map &stream) override
Subclass override.
std::unique_ptr< InboundLedgers > m_inboundLedgers
TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache() override
perf::PerfLog & getPerfLog() override
std::unique_ptr< NetworkIDService > networkIDService_
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.
Routing table for objects identified by hash.
Manages the lifetime of inbound ledgers.
Manages the acquisition and lifetime of transaction sets.
A pool of threads to perform work.
Check the ledger/transaction databases to make sure they have continuity.
Manages the lifetime of ledger replay tasks.
Manages the current fee schedule.
Manages partitions for logging.
Remembers manifests with the highest sequence number.
Service that provides access to the network ID.
Provides server functionality for clients.
A NodeStore::Scheduler which uses the JobQueue.
Persistency layer for NodeObject.
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.
Writable ledger view that accumulates state and tx changes.
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.
Tracks order books in the ledger.
Manages the set of connected peers.
Keeps track of which ledgers haven't been fully saved.
static std::unique_ptr< ResolverAsio > New(boost::asio::io_context &, beast::Journal)
An endpoint that consumes resources.
Tracks load and resource consumption.
Rules controlling protocol behavior.
class to create database, launch online delete thread, and related SQLite database
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.
std::size_t size() const
Returns the number of items in the container.
Manages various times used by the server.
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.
Singleton class that maintains performance counters and optionally writes Json-formatted data to a di...
T hardware_concurrency(T... args)
A namespace for easy access to logging severity values.
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
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.
std::tuple< std::shared_ptr< Ledger >, std::uint32_t, uint256 > getLatestLedger(Rules const &rules, Fees const &fees, ServiceRegistry ®istry)
Fetch the ledger with the highest sequence contained in the database.
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
csprng_engine & crypto_prng()
The default cryptographically secure PRNG.
std::unique_ptr< LedgerCleaner > make_LedgerCleaner(Application &app, beast::Journal journal)
std::unique_ptr< LoadManager > make_LoadManager(Application &app, beast::Journal journal)
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Stopwatch & stopwatch()
Returns an instance of a wall clock.
TxQ::Setup setup_TxQ(Config const &config)
Build a TxQ::Setup object from application configuration.
create_genesis_t const create_genesis
HashRouter::Setup setup_HashRouter(Config const &config)
Create HashRouter setup from configuration.
std::pair< PublicKey, SecretKey > getNodeIdentity(soci::session &session)
Returns a stable public and private key for this node.
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
std::shared_ptr< Ledger > loadByIndex(std::uint32_t ledgerIndex, Rules const &rules, Fees const &fees, ServiceRegistry ®istry, bool acquire)
Load a ledger by its sequence number.
std::unique_ptr< SHAMapStore > make_SHAMapStore(Application &app, NodeStore::Scheduler &scheduler, beast::Journal journal)
std::unique_ptr< PeerSet > make_DummyPeerSet(Application &app)
Make a dummy PeerSet that does not do anything.
std::unique_ptr< AmendmentTable > make_AmendmentTable(ServiceRegistry ®istry, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
std::unique_ptr< CollectorManager > make_CollectorManager(Section const ¶ms, 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)
std::unique_ptr< DatabaseCon > makeWalletDB(DatabaseCon::Setup const &setup, beast::Journal j)
makeWalletDB Opens the wallet database and returns it.
void initAccountIdCache(std::size_t count)
Initialize the global cache used to map AccountID to base58 conversions.
std::unique_ptr< InboundTransactions > make_InboundTransactions(Application &app, beast::insight::Collector::ptr const &collector, std::function< void(std::shared_ptr< SHAMap > const &, bool)> gotSet)
void addJson(Json::Value &json, LedgerFill const &fill)
Given a Ledger and options, fill a Json::Value with a description of the ledger.
MallocTrimReport mallocTrim(std::string_view tag, beast::Journal journal)
Attempt to return freed memory to the operating system.
Overlay::Setup setup_Overlay(BasicConfig const &config)
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
std::shared_ptr< Ledger > loadByHash(uint256 const &ledgerHash, Rules const &rules, Fees const &fees, ServiceRegistry ®istry, bool acquire)
Load a ledger by its hash.
std::unordered_map< std::string, boost::asio::ip::tcp::endpoint > Endpoints
ServerHandler::Setup setup_ServerHandler(Config const &config, std::ostream &log)
std::optional< uint256 > getRegisteredFeature(std::string const &name)
std::unique_ptr< OrderBookDB > make_OrderBookDB(ServiceRegistry ®istry, OrderBookDBConfig const &config)
Create an OrderBookDB instance.
SQLiteDatabase setup_RelationalDatabase(ServiceRegistry ®istry, Config const &config, JobQueue &jobQueue)
setup_RelationalDatabase Creates and returns a SQLiteDatabase instance based on configuration.
std::unique_ptr< PeerSetBuilder > make_PeerSetBuilder(Application &app)
std::unique_ptr< Overlay > make_Overlay(Application &app, Overlay::Setup const &setup, ServerHandler &serverHandler, Resource::Manager &resourceManager, Resolver &resolver, boost::asio::io_context &io_context, BasicConfig const &config, beast::insight::Collector::ptr const &collector)
Creates the implementation of Overlay.
std::unique_ptr< NetworkOPs > make_NetworkOPs(ServiceRegistry ®istry, NetworkOPs::clock_type &clock, bool standalone, std::size_t minPeerCount, bool startValid, JobQueue &jobQueue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_context &ioCtx, beast::Journal journal, beast::insight::Collector::ptr const &collector)
static std::string importNodeDatabase()