1#include <xrpld/core/Config.h>
3#include <xrpl/basics/FileUtilities.h>
4#include <xrpl/basics/Log.h>
5#include <xrpl/basics/StringUtilities.h>
6#include <xrpl/basics/chrono.h>
7#include <xrpl/basics/contract.h>
8#include <xrpl/beast/core/LexicalCast.h>
9#include <xrpl/beast/utility/Journal.h>
10#include <xrpl/beast/utility/instrumentation.h>
11#include <xrpl/config/BasicConfig.h>
12#include <xrpl/config/Constants.h>
13#include <xrpl/net/HTTPClient.h>
14#include <xrpl/protocol/Feature.h>
15#include <xrpl/protocol/SystemParameters.h>
16#include <xrpl/rdb/DBInit.h>
17#include <xrpl/rdb/DatabaseCon.h>
19#include <boost/algorithm/string/classification.hpp>
20#include <boost/algorithm/string/predicate.hpp>
21#include <boost/algorithm/string/replace.hpp>
22#include <boost/algorithm/string/split.hpp>
23#include <boost/algorithm/string/trim.hpp>
24#include <boost/multiprecision/detail/endian.hpp>
25#include <boost/predef.h>
26#include <boost/regex.hpp>
27#include <boost/regex/v5/regex.hpp>
28#include <boost/regex/v5/regex_match.hpp>
53#include <sysinfoapi.h>
57[[nodiscard]] std::uint64_t
60 if (MEMORYSTATUSEX msx{
sizeof(MEMORYSTATUSEX)}; GlobalMemoryStatusEx(&msx))
61 return static_cast<std::uint64_t
>(msx.ullTotalPhys);
71#include <sys/sysinfo.h>
75[[nodiscard]] std::uint64_t
78 if (
struct sysinfo si{}; sysinfo(&si) == 0)
79 return static_cast<std::uint64_t
>(si.totalram) * si.mem_unit;
89#include <sys/sysctl.h>
93[[nodiscard]] std::uint64_t
96 int mib[] = {CTL_HW, HW_MEMSIZE};
98 size_t size =
sizeof(ram);
100 if (sysctl(mib, 2, &ram, &size,
nullptr, 0) == 0)
101 return static_cast<std::uint64_t
>(ram);
114inline constexpr std::array<std::pair<SizedItem, std::array<int, 5>>, 13>
141 []()
constexpr ->
bool {
154 "Mismatch between sized item enum & array indices");
160#define SECTION_DEFAULT_NAME ""
170 boost::algorithm::replace_all(strData,
"\r\n",
"\n");
173 boost::algorithm::replace_all(strData,
"\r",
"\n");
175 boost::algorithm::split(vLines, strData, boost::algorithm::is_any_of(
"\n"));
181 secResult[strSection] = IniFileSections::mapped_type();
184 for (
auto& strValue : vLines)
189 if (strValue.empty() || strValue[0] ==
'#')
193 else if (strValue[0] ==
'[' && strValue[strValue.length() - 1] ==
']')
196 strSection = strValue.
substr(1, strValue.length() - 2);
197 secResult.
emplace(strSection, IniFileSections::mapped_type{});
202 if (!strValue.empty())
203 secResult[strSection].push_back(strValue);
210IniFileSections::mapped_type*
213 if (
auto it = secSource.
find(strSection); it != secSource.
end())
214 return &(it->second);
228 if ((pmtEntries !=
nullptr) && pmtEntries->size() == 1)
230 strValue = (*pmtEntries)[0];
234 if (pmtEntries !=
nullptr)
236 JLOG(j.
warn()) <<
"Section '" << strSection <<
"': requires 1 line not "
237 << pmtEntries->
size() <<
" lines.";
254 if (
auto const v =
std::getenv(name); v !=
nullptr)
268 XRPL_ASSERT(
nodeSize == 0,
"xrpl::Config::setupControl : node size not set");
270 quiet_ = bQuiet || bSilent;
279 auto const& threshold =
283 return (limit == 0) || (ramSize_ < limit);
286 XRPL_ASSERT(ns != threshold.second.end(),
"xrpl::Config::setupControl : valid node size");
288 if (ns != threshold.second.end())
297 XRPL_ASSERT(
nodeSize <= 4,
"xrpl::Config::setupControl : node size is set");
312 if (!strConf.
empty())
340 if (!strHome.empty())
342 auto strXdgConfigHome =
getEnvVar(
"XDG_CONFIG_HOME");
343 auto strXdgDataHome =
getEnvVar(
"XDG_DATA_HOME");
344 if (strXdgConfigHome.empty())
347 strXdgConfigHome = strHome +
"/.config";
349 if (strXdgDataHome.empty())
352 strXdgDataHome = strHome +
"/.local/share";
357 dataDir = strXdgDataHome +
"/" +
systemName();
392 if (!dataDir.
empty())
428 auto const& section = config[name];
436 ss <<
"Invalid value '" << *optResult <<
"' for key 'port' in [" << name <<
"]";
483 for (
auto& line : strVec)
486 if (
std::count(line.begin(), line.end(),
':') != 1)
492 if (result.
size() == line.size())
514 if (strTemp ==
"main")
518 else if (strTemp ==
"testnet")
522 else if (strTemp ==
"devnet")
545 if (*peersInMaxOpt > 1000)
548 "Invalid value specified in [{}] section; the value must be less or equal than "
558 if (*peersOutMaxOpt < 10 || *peersOutMaxOpt > 1000)
561 "Invalid value specified in [{}] section; the value must be in range 10-1000",
567 if ((peersInMaxOpt && !peersOutMaxOpt) || (peersOutMaxOpt && !peersInMaxOpt))
570 "Both sections [{}] and [{}] must be configured",
575 if (peersInMaxOpt && peersOutMaxOpt)
584 if (boost::iequals(strTemp,
"tiny"))
588 else if (boost::iequals(strTemp,
"small"))
592 else if (boost::iequals(strTemp,
"medium"))
596 else if (boost::iequals(strTemp,
"large"))
600 else if (boost::iequals(strTemp,
"huge"))
624 if (boost::iequals(strTemp,
"all"))
628 else if (boost::iequals(strTemp,
"trusted"))
632 else if (boost::iequals(strTemp,
"drop_untrusted"))
645 if (boost::iequals(strTemp,
"all"))
649 else if (boost::iequals(strTemp,
"trusted"))
653 else if (boost::iequals(strTemp,
"drop_untrusted"))
667 "Cannot have both [{}] and [{}] config sections",
687 if (boost::iequals(strTemp,
"full"))
691 else if (boost::iequals(strTemp,
"none"))
703 if (boost::iequals(strTemp,
"none"))
707 else if (boost::iequals(strTemp,
"full"))
801 "Invalid {} cannot specify both vp_base_squelch_enable and vp_enable options. "
802 "vp_enable was deprecated and replaced by vp_base_squelch_enable",
832 "Invalid {} vp_base_squelch_max_selected_peers must be greater than or equal to 3",
846 "Invalid {}, tx_min_peers must be greater than or equal to 10, tx_relay_percentage "
847 "must be greater than or equal to 10 and less than or equal to 100",
863 "Invalid {}: the domain name does not appear to meet the requirements.",
884 "Invalid value 'max_unknown_time' in {}: must be of the form '<number>' "
885 "representing seconds.",
892 "Invalid value 'max_unknown_time' in {}: the time must be between 300 and 1800 "
893 "seconds, inclusive.",
905 "Invalid value 'max_diverged_time' in {}: must be of the form '<number>' "
906 "representing seconds.",
913 "Invalid value 'max_diverged_time' in {}: the time must be between 60 and 900 "
914 "seconds, inclusive.",
926 if (
auto val = sec.get(key))
932 "Invalid value '{}' in {}: must be of the form '<number>' representing a count "
941 "Invalid value '{}' in {}: the count must be between {} and {}, inclusive.",
958 boost::regex
const re(R
"(^\s*(\d+)\s*(minutes|hours|days|weeks)\s*(\s+.*)?$)");
960 if (!boost::regex_match(strTemp, match, re))
963 "Invalid {}, must be: [0-9]+ [minutes|hours|days|weeks]",
969 if (boost::iequals(match[2],
"minutes"))
973 else if (boost::iequals(match[2],
"hours"))
977 else if (boost::iequals(match[2],
"days"))
981 else if (boost::iequals(match[2],
"weeks"))
989 "Invalid {}, the minimum amount of time an amendment must hold a majority is 15 "
1013 validatorsFile = strTemp;
1015 if (validatorsFile.
empty())
1022 validatorsFile =
configDir / validatorsFile;
1027 "The file specified in [{}] does not exist: {}",
1029 validatorsFile.
string()));
1036 "Invalid file specified in [{}]: {}",
1038 validatorsFile.
string()));
1045 if (!validatorsFile.
empty())
1051 validatorsFile.
clear();
1065 "Failed to read '{}': {} (error {})",
1075 if (entries !=
nullptr)
1080 if (valKeyEntries !=
nullptr)
1085 if (valSiteEntries !=
nullptr)
1090 if (valListKeys !=
nullptr)
1095 if (valListThreshold !=
nullptr)
1098 if ((entries ==
nullptr) && (valKeyEntries ==
nullptr) && (valListKeys ==
nullptr))
1101 "The file specified in [{}] does not contain a [{}], [{}] or [{}] section: {}",
1106 validatorsFile.
string()));
1112 if (listThreshold.lines().empty())
1114 return std::nullopt;
1116 if (listThreshold.values().size() == 1)
1118 auto strTemp = listThreshold.values()[0];
1120 if (listThreshold == 0)
1122 return std::nullopt;
1127 "Value in config section [{}] exceeds the number of configured list keys",
1130 return listThreshold;
1134 "Config section [{}] should contain single value only",
1151 for (
auto const& s : part.values())
1177 "The minimum number of required peers (network_quorum) exceeds "
1178 "the maximum number of allowed peers (peers_max)");
1188 if (!logFile.empty() && !logFile.is_absolute())
1195 if (!logFile.empty())
1197 auto logDir = logFile.parent_path();
1208 std::cerr <<
"Unable to create log file path " << logDir <<
": " << ec.
message()
1221 XRPL_ASSERT(index <
kSizedItems.size(),
"xrpl::Config::getValueFor : valid index input");
1222 XRPL_ASSERT(!node || *node <= 4,
"xrpl::Config::getValueFor : unset or valid node");
1270 bool showRiskWarning =
false;
1272 if (
set(safetyLevel,
"safety_level", sqlite))
1274 if (boost::iequals(safetyLevel,
"low"))
1277 journalMode =
"memory";
1278 synchronous =
"off";
1279 tempStore =
"memory";
1280 showRiskWarning =
true;
1282 else if (!boost::iequals(safetyLevel,
"high"))
1285 std::format(
"Invalid safety_level value: {}", safetyLevel));
1292 if (
set(journalMode,
"journal_mode", sqlite) && !safetyLevel.
empty())
1295 "Configuration file may not define both "
1296 "\"safety_level\" and \"journal_mode\"");
1298 bool const higherRisk =
1299 boost::iequals(journalMode,
"memory") || boost::iequals(journalMode,
"off");
1300 showRiskWarning = showRiskWarning || higherRisk;
1301 if (higherRisk || boost::iequals(journalMode,
"delete") ||
1302 boost::iequals(journalMode,
"truncate") || boost::iequals(journalMode,
"persist") ||
1303 boost::iequals(journalMode,
"wal"))
1310 std::format(
"Invalid journal_mode value: {}", journalMode));
1316 if (
set(synchronous,
"synchronous", sqlite) && !safetyLevel.
empty())
1319 "Configuration file may not define both "
1320 "\"safety_level\" and \"synchronous\"");
1322 bool const higherRisk = boost::iequals(synchronous,
"off");
1323 showRiskWarning = showRiskWarning || higherRisk;
1324 if (higherRisk || boost::iequals(synchronous,
"normal") ||
1325 boost::iequals(synchronous,
"full") || boost::iequals(synchronous,
"extra"))
1332 std::format(
"Invalid synchronous value: {}", synchronous));
1338 if (
set(tempStore,
"temp_store", sqlite) && !safetyLevel.
empty())
1341 "Configuration file may not define both "
1342 "\"safety_level\" and \"temp_store\"");
1344 bool const higherRisk = boost::iequals(tempStore,
"memory");
1345 showRiskWarning = showRiskWarning || higherRisk;
1346 if (higherRisk || boost::iequals(tempStore,
"default") ||
1347 boost::iequals(tempStore,
"file"))
1359 JLOG(j->warn()) <<
"reducing the data integrity guarantees from the "
1360 "default [sqlite] behavior is not recommended for "
1361 "nodes storing large amounts of history, because of the "
1362 "difficulty inherent in rebuilding corrupted data.";
1365 result->size() == 3,
"xrpl::setup_DatabaseCon::globalPragma : result size is 3");
1375 setPragma(setup.
lgrPragma[0],
"journal_size_limit", 1582080);
1379 int64_t journalSizeLimit = 1582080;
1385 if (pageSize < 512 || pageSize > 65536)
1388 if ((pageSize & (pageSize - 1)) != 0)
1392 setPragma(setup.
txPragma[0],
"page_size", pageSize);
1393 setPragma(setup.
txPragma[1],
"journal_size_limit", journalSizeLimit);
1394 setPragma(setup.
txPragma[2],
"max_page_count", 4294967294);
1395 setPragma(setup.
txPragma[3],
"mmap_size", 17179869184);
A generic endpoint for log messages.
void build(IniFileSections const &ifs)
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
void legacy(std::string const §ion, std::string value)
Set a value that is not a key/value pair.
Section & section(std::string const &name)
Returns the section with the given name.
static constexpr int kMinJobQueueTx
std::filesystem::path configFile_
std::unordered_set< UInt256, beast::Uhash<> > features
static constexpr std::string_view kConfigLegacyName
std::optional< std::size_t > maxUntrustedCount
std::chrono::seconds maxDivergedTime
static constexpr int kMaxJobQueueTx
std::optional< int > sweepInterval
std::size_t txReduceRelayMinPeers
static constexpr std::size_t kMinManifestCount
std::optional< std::size_t > maxTrustedCount
static constexpr std::string_view kDatabaseDirName
std::size_t vpReduceRelaySquelchMaxSelectedPeers
////////////////// !
static constexpr std::string_view kConfigFileName
std::filesystem::path getDebugLogFile() const
Returns the full path and filename of the debug log file.
static constexpr std::size_t kMaxManifestCount
void setup(std::string const &strConf, bool bQuiet, bool bSilent, bool bStandalone)
std::chrono::seconds maxUnknownTime
std::uint64_t const ramSize_
int relayUntrustedProposals
int relayUntrustedValidations
std::vector< std::string > ipsFixed
bool vpReduceRelayBaseSquelchEnable
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
std::string sslVerifyFile
std::optional< std::size_t > maxSubscriptionsPerConnection
std::size_t txRelayPercentage
bool txReduceRelayMetrics
std::optional< std::size_t > validatorListThreshold
std::filesystem::path debugLogfile_
bool runStandalone_
Operate in stand-alone mode.
static constexpr std::string_view kValidatorsFileName
bool txReduceRelayEnable
////////////// END OF TEMPORARY CODE BLOCK /////////////////////
std::vector< std::string > ips
bool signingEnabled_
Determines if the server will sign a tx, given an account's secret seed.
void setupControl(bool bQuiet, bool bSilent, bool bStandalone)
std::uint32_t ledgerHistory
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
std::size_t networkQuorum
std::filesystem::path configDir
std::chrono::seconds amendmentMajorityTime
static void initializeSSLContext(std::string const &sslVerifyDir, std::string const &sslVerifyFile, bool sslVerify, beast::Journal j)
Holds a collection of configuration values.
std::vector< std::string > const & values() const
Returns all the values in the section.
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
T create_directories(T... args)
T current_path(T... args)
T hardware_concurrency(T... args)
T is_directory(T... args)
T is_regular_file(T... args)
constexpr Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
constexpr Out lexicalCast(In in, Out defaultValue=Out())
Convert from one type to another.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
constexpr std::uint32_t kSqliteTuningCutoff
std::chrono::duration< int, std::ratio_multiply< std::chrono::hours::period, std::ratio< 24 > > > Days
bool isProperlyFormedTomlDomain(std::string_view domain)
Determines if the given string looks like a TOML-file hosting domain.
static std::string getEnvVar(char const *name)
std::optional< UInt256 > getRegisteredFeature(std::string const &name)
FeeSetup setupFeeVote(Section const §ion)
bool getSingleSection(IniFileSections &secSource, std::string const &strSection, std::string &strValue, beast::Journal j)
IniFileSections::mapped_type * getIniFileSection(IniFileSections &secSource, std::string const &strSection)
constexpr std::array< std::pair< SizedItem, std::array< int, 5 > >, 13 > kSizedItems
IniFileSections parseIniFile(std::string const &strInput, bool const bTrim)
bool getIfExists(Section const §ion, std::string const &name, T &v)
std::string commonDbPragmaJournal(std::string_view journalMode)
std::string trimWhitespace(std::string str)
Remove leading and trailing ASCII whitespace.
std::string commonDbPragmaTemp(std::string_view tempStore)
static std::string const & systemName()
std::string getFileContents(std::error_code &ec, std::filesystem::path const &sourcePath, std::optional< std::size_t > maxSize=std::nullopt)
static void checkZeroPorts(Config const &config)
DatabaseCon::Setup setupDatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
std::chrono::duration< int, std::ratio_multiply< Days::period, std::ratio< 7 > > > Weeks
std::unordered_map< std::string, std::vector< std::string > > IniFileSections
std::string commonDbPragmaSync(std::string_view synchronous)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
T regex_replace(T... args)
std::array< std::string, 4 > txPragma
static std::unique_ptr< std::vector< std::string > const > globalPragma
std::filesystem::path dataDir
std::array< std::string, 1 > lgrPragma
Fee schedule for startup / standalone, and to vote for.
XRPAmount accountReserve
The account reserve requirement in drops.
XRPAmount ownerReserve
The per-owned item reserve requirement in drops.
XRPAmount referenceFee
The cost of a reference transaction in drops.
static constexpr auto kPageSize
static constexpr auto kTxRelayPercentage
static constexpr auto kFastLoad
static constexpr auto kTxMetrics
static constexpr auto kAccountReserve
static constexpr auto kUseTxTables
static constexpr auto kReferenceFee
static constexpr auto kVpBaseSquelchEnable
static constexpr auto kPort
static constexpr auto kMaxUnknownTime
static constexpr auto kJournalSizeLimit
static constexpr auto kTxMinPeers
static constexpr auto kVpEnable
static constexpr auto kMaxTrustedCount
static constexpr auto kMaxUntrustedCount
static constexpr auto kVpBaseSquelchMaxSelectedPeers
static constexpr auto kMaxDivergedTime
static constexpr auto kTxEnable
static constexpr auto kOwnerReserve
static constexpr auto kAmendmentMajorityTime
static constexpr auto kMaxSubscriptionsPerConnection
static constexpr auto kPeersInMax
static constexpr auto kMaxTransactions
static constexpr auto kRelayProposals
static constexpr auto kSweepInterval
static constexpr auto kNodeSize
static constexpr auto kServerDomain
static constexpr auto kIps
static constexpr auto kOverlay
static constexpr auto kReduceRelay
static constexpr auto kValidatorListThreshold
static constexpr auto kValidators
static constexpr auto kSslVerifyFile
static constexpr auto kValidatorListKeys
static constexpr auto kSslVerifyDir
static constexpr auto kNetworkQuorum
static constexpr auto kValidationSeed
static constexpr auto kSigningSupport
static constexpr auto kCompression
static constexpr auto kPeersMax
static constexpr auto kPathSearchOld
static constexpr auto kServer
static constexpr auto kLedgerHistory
static constexpr auto kElbSupport
static constexpr auto kValidatorKeys
static constexpr auto kPeerPrivate
static constexpr auto kSslVerify
static constexpr auto kPeersOutMax
static constexpr auto kFeeDefault
static constexpr auto kValidatorsFile
static constexpr auto kPathSearchMax
static constexpr auto kRelayValidations
static constexpr auto kNodeDatabase
static constexpr auto kIpsFixed
static constexpr auto kDatabasePath
static constexpr auto kPathSearch
static constexpr auto kLedgerReplay
static constexpr auto kPrefetchWorkers
static constexpr auto kDebugLogfile
static constexpr auto kSqlite
static constexpr auto kValidatorToken
static constexpr auto kPathSearchFast
static constexpr auto kVoting
static constexpr auto kLedgerTxTables
static constexpr auto kBetaRpcApi
static constexpr auto kIoWorkers
static constexpr auto kFetchDepth
static constexpr auto kValidatorListSites
static constexpr auto kWorkers
static constexpr auto kNetworkId
static constexpr auto kFeatures