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/filesystem/operations.hpp>
25#include <boost/filesystem/path.hpp>
26#include <boost/format/free_funcs.hpp>
27#include <boost/multiprecision/detail/endian.hpp>
28#include <boost/predef.h>
29#include <boost/regex.hpp>
30#include <boost/regex/v5/regex.hpp>
31#include <boost/regex/v5/regex_match.hpp>
32#include <boost/system/detail/error_code.hpp>
54#include <sysinfoapi.h>
58[[nodiscard]] std::uint64_t
61 if (MEMORYSTATUSEX msx{
sizeof(MEMORYSTATUSEX)}; GlobalMemoryStatusEx(&msx))
62 return static_cast<std::uint64_t
>(msx.ullTotalPhys);
72#include <sys/sysinfo.h>
76[[nodiscard]] std::uint64_t
79 if (
struct sysinfo si{}; sysinfo(&si) == 0)
80 return static_cast<std::uint64_t
>(si.totalram) * si.mem_unit;
90#include <sys/sysctl.h>
94[[nodiscard]] std::uint64_t
97 int mib[] = {CTL_HW, HW_MEMSIZE};
99 size_t size =
sizeof(ram);
101 if (sysctl(mib, 2, &ram, &size, NULL, 0) == 0)
102 return static_cast<std::uint64_t
>(ram);
115inline constexpr std::array<std::pair<SizedItem, std::array<int, 5>>, 13>
142 []()
constexpr ->
bool {
155 "Mismatch between sized item enum & array indices");
161#define SECTION_DEFAULT_NAME ""
171 boost::algorithm::replace_all(strData,
"\r\n",
"\n");
174 boost::algorithm::replace_all(strData,
"\r",
"\n");
176 boost::algorithm::split(vLines, strData, boost::algorithm::is_any_of(
"\n"));
182 secResult[strSection] = IniFileSections::mapped_type();
185 for (
auto& strValue : vLines)
188 boost::algorithm::trim(strValue);
190 if (strValue.empty() || strValue[0] ==
'#')
194 else if (strValue[0] ==
'[' && strValue[strValue.length() - 1] ==
']')
197 strSection = strValue.
substr(1, strValue.length() - 2);
198 secResult.
emplace(strSection, IniFileSections::mapped_type{});
203 if (!strValue.empty())
204 secResult[strSection].push_back(strValue);
211IniFileSections::mapped_type*
214 if (
auto it = secSource.
find(strSection); it != secSource.
end())
215 return &(it->second);
229 if ((pmtEntries !=
nullptr) && pmtEntries->size() == 1)
231 strValue = (*pmtEntries)[0];
235 if (pmtEntries !=
nullptr)
237 JLOG(j.
warn()) <<
"Section '" << strSection <<
"': requires 1 line not "
238 << pmtEntries->
size() <<
" lines.";
260 if (
auto const v =
std::getenv(name); v !=
nullptr)
274 XRPL_ASSERT(
nodeSize == 0,
"xrpl::Config::setupControl : node size not set");
276 quiet_ = bQuiet || bSilent;
285 auto const& threshold =
289 return (limit == 0) || (ramSize_ < limit);
292 XRPL_ASSERT(ns != threshold.second.end(),
"xrpl::Config::setupControl : valid node size");
294 if (ns != threshold.second.end())
303 XRPL_ASSERT(
nodeSize <= 4,
"xrpl::Config::setupControl : node size is set");
316 boost::filesystem::path dataDir;
318 if (!strConf.
empty())
333 configDir = boost::filesystem::current_path();
346 if (!strHome.empty())
348 auto strXdgConfigHome =
getEnvVar(
"XDG_CONFIG_HOME");
349 auto strXdgDataHome =
getEnvVar(
"XDG_DATA_HOME");
350 if (strXdgConfigHome.empty())
353 strXdgConfigHome = strHome +
"/.config";
355 if (strXdgDataHome.empty())
358 strXdgDataHome = strHome +
"/.local/share";
363 dataDir = strXdgDataHome +
"/" +
systemName();
390 dataDir = boost::filesystem::path(dbPath);
398 if (!dataDir.empty())
400 boost::system::error_code ec;
401 boost::filesystem::create_directories(dataDir, ec);
434 auto const& section = config[name];
442 ss <<
"Invalid value '" << *optResult <<
"' for key 'port' in [" << name <<
"]";
458 boost::system::error_code ec;
489 for (
auto& line : strVec)
492 if (
std::count(line.begin(), line.end(),
':') != 1)
498 if (result.
size() == line.size())
511 boost::filesystem::path
const p(dbPath);
520 if (strTemp ==
"main")
524 else if (strTemp ==
"testnet")
528 else if (strTemp ==
"devnet")
551 if (*peersInMaxOpt > 1000)
555 "] section; the value must be less or equal than 1000");
563 if (*peersOutMaxOpt < 10 || *peersOutMaxOpt > 1000)
567 "] section; the value must be in range 10-1000");
572 if ((peersInMaxOpt && !peersOutMaxOpt) || (peersOutMaxOpt && !peersInMaxOpt))
579 if (peersInMaxOpt && peersOutMaxOpt)
588 if (boost::iequals(strTemp,
"tiny"))
592 else if (boost::iequals(strTemp,
"small"))
596 else if (boost::iequals(strTemp,
"medium"))
600 else if (boost::iequals(strTemp,
"large"))
604 else if (boost::iequals(strTemp,
"huge"))
628 if (boost::iequals(strTemp,
"all"))
632 else if (boost::iequals(strTemp,
"trusted"))
636 else if (boost::iequals(strTemp,
"drop_untrusted"))
650 if (boost::iequals(strTemp,
"all"))
654 else if (boost::iequals(strTemp,
"trusted"))
658 else if (boost::iequals(strTemp,
"drop_untrusted"))
689 if (boost::iequals(strTemp,
"full"))
693 else if (boost::iequals(strTemp,
"none"))
705 if (boost::iequals(strTemp,
"none"))
709 else if (boost::iequals(strTemp,
"full"))
746 ": must be between 10 and 600 inclusive");
758 ": must be between 1 and 1024 inclusive.");
770 ": must be between 1 and 1024 inclusive.");
782 ": must be between 1 and 1024 inclusive.");
806 " cannot specify both vp_base_squelch_enable and vp_enable "
808 "vp_enable was deprecated and replaced by "
809 "vp_base_squelch_enable");
835 " vp_base_squelch_max_selected_peers must be "
836 "greater than or equal to 3");
848 ", tx_min_peers must be greater than or equal to 10"
849 ", tx_relay_percentage must be greater than or equal to 10 "
850 "and less than or equal to 100");
866 ": the domain name does not appear to meet the requirements.");
887 ": must be of the form '<number>' representing seconds.");
894 ": the time must be between 300 and 1800 seconds, inclusive.");
906 ": must be of the form '<number>' representing seconds.");
913 ": the time must be between 60 and 900 seconds, inclusive.");
920 boost::regex
const re(
"^\\s*(\\d+)\\s*(minutes|hours|days|weeks)\\s*(\\s+.*)?$");
922 if (!boost::regex_match(strTemp, match, re))
926 ", must be: [0-9]+ [minutes|hours|days|weeks]");
931 if (boost::iequals(match[2],
"minutes"))
935 else if (boost::iequals(match[2],
"hours"))
939 else if (boost::iequals(match[2],
"days"))
943 else if (boost::iequals(match[2],
"weeks"))
952 ", the minimum amount of time an amendment must hold a "
953 "majority is 15 minutes");
971 boost::filesystem::path validatorsFile;
975 validatorsFile = strTemp;
977 if (validatorsFile.empty())
983 if (!validatorsFile.is_absolute() && !
configDir.empty())
984 validatorsFile =
configDir / validatorsFile;
986 if (!boost::filesystem::exists(validatorsFile))
992 validatorsFile.string());
995 !boost::filesystem::is_regular_file(validatorsFile) &&
996 !boost::filesystem::is_symlink(validatorsFile))
1000 "]: " + validatorsFile.string());
1007 if (!validatorsFile.empty())
1009 if (!boost::filesystem::exists(validatorsFile) ||
1010 (!boost::filesystem::is_regular_file(validatorsFile) &&
1011 !boost::filesystem::is_symlink(validatorsFile)))
1013 validatorsFile.clear();
1018 if (!validatorsFile.empty() && boost::filesystem::exists(validatorsFile) &&
1019 (boost::filesystem::is_regular_file(validatorsFile) ||
1020 boost::filesystem::is_symlink(validatorsFile)))
1022 boost::system::error_code ec;
1027 "Failed to read '" + validatorsFile.string() +
"'." +
1035 if (entries !=
nullptr)
1040 if (valKeyEntries !=
nullptr)
1045 if (valSiteEntries !=
nullptr)
1050 if (valListKeys !=
nullptr)
1055 if (valListThreshold !=
nullptr)
1058 if ((entries ==
nullptr) && (valKeyEntries ==
nullptr) && (valListKeys ==
nullptr))
1063 "does not contain a [" +
1073 validatorsFile.string());
1079 if (listThreshold.lines().empty())
1081 return std::nullopt;
1083 if (listThreshold.values().size() == 1)
1085 auto strTemp = listThreshold.values()[0];
1087 if (listThreshold == 0)
1089 return std::nullopt;
1095 "Value in config section "
1098 "] exceeds the number of configured list keys");
1100 return listThreshold;
1123 for (
auto const& s : part.values())
1149 "The minimum number of required peers (network_quorum) exceeds "
1150 "the maximum number of allowed peers (peers_max)");
1155boost::filesystem::path
1160 if (!logFile.empty() && !logFile.is_absolute())
1164 logFile = boost::filesystem::absolute(logFile,
configDir);
1167 if (!logFile.empty())
1169 auto logDir = logFile.parent_path();
1171 if (!boost::filesystem::is_directory(logDir))
1173 boost::system::error_code ec;
1174 boost::filesystem::create_directories(logDir, ec);
1180 std::cerr <<
"Unable to create log file path " << logDir <<
": " << ec.message()
1193 XRPL_ASSERT(index <
kSizedItems.size(),
"xrpl::Config::getValueFor : valid index input");
1194 XRPL_ASSERT(!node || *node <= 4,
"xrpl::Config::getValueFor : unset or valid node");
1242 bool showRiskWarning =
false;
1244 if (
set(safetyLevel,
"safety_level", sqlite))
1246 if (boost::iequals(safetyLevel,
"low"))
1249 journalMode =
"memory";
1250 synchronous =
"off";
1251 tempStore =
"memory";
1252 showRiskWarning =
true;
1254 else if (!boost::iequals(safetyLevel,
"high"))
1263 if (
set(journalMode,
"journal_mode", sqlite) && !safetyLevel.
empty())
1266 "Configuration file may not define both "
1267 "\"safety_level\" and \"journal_mode\"");
1269 bool const higherRisk =
1270 boost::iequals(journalMode,
"memory") || boost::iequals(journalMode,
"off");
1271 showRiskWarning = showRiskWarning || higherRisk;
1272 if (higherRisk || boost::iequals(journalMode,
"delete") ||
1273 boost::iequals(journalMode,
"truncate") || boost::iequals(journalMode,
"persist") ||
1274 boost::iequals(journalMode,
"wal"))
1276 result->emplace_back(
1287 if (
set(synchronous,
"synchronous", sqlite) && !safetyLevel.
empty())
1290 "Configuration file may not define both "
1291 "\"safety_level\" and \"synchronous\"");
1293 bool const higherRisk = boost::iequals(synchronous,
"off");
1294 showRiskWarning = showRiskWarning || higherRisk;
1295 if (higherRisk || boost::iequals(synchronous,
"normal") ||
1296 boost::iequals(synchronous,
"full") || boost::iequals(synchronous,
"extra"))
1308 if (
set(tempStore,
"temp_store", sqlite) && !safetyLevel.
empty())
1311 "Configuration file may not define both "
1312 "\"safety_level\" and \"temp_store\"");
1314 bool const higherRisk = boost::iequals(tempStore,
"memory");
1315 showRiskWarning = showRiskWarning || higherRisk;
1316 if (higherRisk || boost::iequals(tempStore,
"default") ||
1317 boost::iequals(tempStore,
"file"))
1329 JLOG(j->warn()) <<
"reducing the data integrity guarantees from the "
1330 "default [sqlite] behavior is not recommended for "
1331 "nodes storing large amounts of history, because of the "
1332 "difficulty inherent in rebuilding corrupted data.";
1335 result->size() == 3,
"xrpl::setup_DatabaseCon::globalPragma : result size is 3");
1345 setPragma(setup.
lgrPragma[0],
"journal_size_limit", 1582080);
1349 int64_t journalSizeLimit = 1582080;
1355 if (pageSize < 512 || pageSize > 65536)
1358 if ((pageSize & (pageSize - 1)) != 0)
1362 setPragma(setup.
txPragma[0],
"page_size", pageSize);
1363 setPragma(setup.
txPragma[1],
"journal_size_limit", journalSizeLimit);
1364 setPragma(setup.
txPragma[2],
"max_page_count", 4294967294);
1365 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::chrono::seconds maxDivergedTime
std::unordered_set< uint256, beast::Uhash<> > features
static constexpr int kMaxJobQueueTx
std::optional< int > sweepInterval
std::size_t txReduceRelayMinPeers
boost::filesystem::path configFile_
std::size_t vpReduceRelaySquelchMaxSelectedPeers
void setup(std::string const &strConf, bool bQuiet, bool bSilent, bool bStandalone)
std::chrono::seconds maxUnknownTime
static char const *const kDatabaseDirName
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::size_t txRelayPercentage
bool txReduceRelayMetrics
boost::filesystem::path getDebugLogFile() const
Returns the full path and filename of the debug log file.
static char const *const kConfigLegacyName
std::optional< std::size_t > validatorListThreshold
bool runStandalone_
Operate in stand-alone mode.
boost::filesystem::path configDir
static char const *const kConfigFileName
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
boost::filesystem::path debugLogfile_
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.
static char const *const kValidatorsFileName
std::size_t networkQuorum
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 hardware_concurrency(T... args)
Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
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::string getFileContents(boost::system::error_code &ec, boost::filesystem::path const &sourcePath, std::optional< std::size_t > maxSize=std::nullopt)
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)
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::chrono::duration< int, std::ratio_multiply< days::period, std::ratio< 7 > > > weeks
constexpr char const * kCommonDbPragmaSync
static std::string const & systemName()
constexpr char const * kCommonDbPragmaTemp
static void checkZeroPorts(Config const &config)
std::chrono::duration< int, std::ratio_multiply< std::chrono::hours::period, std::ratio< 24 > > > days
DatabaseCon::Setup setupDatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
constexpr char const * kCommonDbPragmaJournal
std::optional< uint256 > getRegisteredFeature(std::string const &name)
std::unordered_map< std::string, std::vector< std::string > > IniFileSections
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
boost::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 kVpBaseSquelchMaxSelectedPeers
static constexpr auto kMaxDivergedTime
static constexpr auto kTxEnable
static constexpr auto kOwnerReserve
static constexpr auto kAmendmentMajorityTime
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