20 #include <ripple/basics/FileUtilities.h>
21 #include <ripple/basics/Log.h>
22 #include <ripple/basics/contract.h>
23 #include <ripple/beast/core/LexicalCast.h>
24 #include <ripple/core/Config.h>
25 #include <ripple/core/ConfigSections.h>
26 #include <ripple/json/json_reader.h>
27 #include <ripple/net/HTTPClient.h>
28 #include <ripple/protocol/Feature.h>
29 #include <ripple/protocol/SystemParameters.h>
30 #include <boost/algorithm/string.hpp>
31 #include <boost/beast/core/string.hpp>
32 #include <boost/format.hpp>
33 #include <boost/regex.hpp>
34 #include <boost/system/error_code.hpp>
64 []() constexpr->bool {
65 std::underlying_type_t<SizedItem> idx = 0;
67 for (auto const& i : sizedItems)
69 if (static_cast<std::underlying_type_t<SizedItem>>(i.first) != idx)
77 "Mismatch between sized item enum & array indices");
83 #define SECTION_DEFAULT_NAME ""
93 boost::algorithm::replace_all(strData,
"\r\n",
"\n");
96 boost::algorithm::replace_all(strData,
"\r",
"\n");
98 boost::algorithm::split(vLines, strData, boost::algorithm::is_any_of(
"\n"));
104 secResult[strSection] = IniFileSections::mapped_type();
107 for (
auto& strValue : vLines)
110 boost::algorithm::trim(strValue);
112 if (strValue.empty() || strValue[0] ==
'#')
116 else if (strValue[0] ==
'[' && strValue[strValue.length() - 1] ==
']')
119 strSection = strValue.
substr(1, strValue.length() - 2);
120 secResult.
emplace(strSection, IniFileSections::mapped_type{});
125 if (!strValue.empty())
126 secResult[strSection].push_back(strValue);
133 IniFileSections::mapped_type*
136 IniFileSections::iterator it;
137 IniFileSections::mapped_type* smtResult;
138 it = secSource.
find(strSection);
139 if (it == secSource.
end())
142 smtResult = &(it->second);
153 IniFileSections::mapped_type* pmtEntries =
155 bool bSingle = pmtEntries && 1 == pmtEntries->size();
159 strValue = (*pmtEntries)[0];
163 JLOG(j.
warn()) << boost::str(
164 boost::format(
"Section [%s]: requires 1 line not %d lines.") %
165 strSection % pmtEntries->
size());
177 char const*
const Config::configFileName =
"rippled.cfg";
178 char const*
const Config::databaseDirName =
"db";
179 char const*
const Config::validatorsFileName =
"validators.txt";
186 auto const v = getenv(name);
194 constexpr FeeUnit32 Config::TRANSACTION_FEE_BASE;
197 Config::setupControl(
bool bQuiet,
bool bSilent,
bool bStandalone)
199 QUIET = bQuiet || bSilent;
201 RUN_STANDALONE = bStandalone;
211 boost::filesystem::path dataDir;
220 setupControl(bQuiet, bSilent, bStandalone);
222 strDbPath = databaseDirName;
224 if (!strConf.
empty())
225 strConfFile = strConf;
227 strConfFile = configFileName;
229 if (!strConf.
empty())
232 CONFIG_FILE = strConfFile;
233 CONFIG_DIR = boost::filesystem::absolute(CONFIG_FILE);
234 CONFIG_DIR.remove_filename();
235 dataDir = CONFIG_DIR / strDbPath;
239 CONFIG_DIR = boost::filesystem::current_path();
240 CONFIG_FILE = CONFIG_DIR / strConfFile;
241 dataDir = CONFIG_DIR / strDbPath;
249 if (boost::filesystem::exists(CONFIG_FILE)
251 || (strHome.
empty() &&
252 (strXdgConfigHome.
empty() || strXdgDataHome.
empty())))
258 if (strXdgConfigHome.
empty())
261 strXdgConfigHome = strHome +
"/.config";
264 if (strXdgDataHome.
empty())
267 strXdgDataHome = strHome +
"/.local/share";
270 CONFIG_DIR = strXdgConfigHome +
"/" + systemName();
271 CONFIG_FILE = CONFIG_DIR / strConfFile;
272 dataDir = strXdgDataHome +
"/" + systemName();
274 if (!boost::filesystem::exists(CONFIG_FILE))
276 CONFIG_DIR =
"/etc/opt/" + systemName();
277 CONFIG_FILE = CONFIG_DIR / strConfFile;
278 dataDir =
"/var/opt/" + systemName();
289 dataDir = boost::filesystem::path(dbPath);
290 else if (RUN_STANDALONE)
294 if (!dataDir.empty())
296 boost::system::error_code ec;
297 boost::filesystem::create_directories(dataDir, ec);
300 Throw<std::runtime_error>(
301 boost::str(boost::format(
"Can not create %s") % dataDir));
303 legacy(
"database_path", boost::filesystem::absolute(dataDir).
string());
306 HTTPClient::initializeSSLContext(*
this, j_);
319 std::cerr <<
"Loading: " << CONFIG_FILE <<
"\n";
321 boost::system::error_code ec;
326 std::cerr <<
"Failed to read '" << CONFIG_FILE <<
"'." << ec.value()
331 loadFromString(fileContents);
354 boost::filesystem::path p(dbPath);
355 legacy(
"database_path", boost::filesystem::absolute(p).
string());
362 PEER_PRIVATE = beast::lexicalCastThrow<bool>(strTemp);
365 PEERS_MAX = beast::lexicalCastThrow<std::size_t>(strTemp);
369 if (boost::iequals(strTemp,
"tiny"))
371 else if (boost::iequals(strTemp,
"small"))
373 else if (boost::iequals(strTemp,
"medium"))
375 else if (boost::iequals(strTemp,
"large"))
377 else if (boost::iequals(strTemp,
"huge"))
380 NODE_SIZE = std::min<std::size_t>(
381 4, beast::lexicalCastThrow<std::size_t>(strTemp));
385 signingEnabled_ = beast::lexicalCastThrow<bool>(strTemp);
388 ELB_SUPPORT = beast::lexicalCastThrow<bool>(strTemp);
391 WEBSOCKET_PING_FREQ =
398 SSL_VERIFY = beast::lexicalCastThrow<bool>(strTemp);
402 if (boost::iequals(strTemp,
"all"))
403 RELAY_UNTRUSTED_VALIDATIONS =
true;
404 else if (boost::iequals(strTemp,
"trusted"))
405 RELAY_UNTRUSTED_VALIDATIONS =
false;
407 Throw<std::runtime_error>(
408 "Invalid value specified in [" SECTION_RELAY_VALIDATIONS
414 if (boost::iequals(strTemp,
"all"))
415 RELAY_UNTRUSTED_PROPOSALS =
true;
416 else if (boost::iequals(strTemp,
"trusted"))
417 RELAY_UNTRUSTED_PROPOSALS =
false;
419 Throw<std::runtime_error>(
420 "Invalid value specified in [" SECTION_RELAY_PROPOSALS
424 if (exists(SECTION_VALIDATION_SEED) && exists(SECTION_VALIDATOR_TOKEN))
425 Throw<std::runtime_error>(
"Cannot have both [" SECTION_VALIDATION_SEED
427 "and [" SECTION_VALIDATOR_TOKEN
428 "] config sections");
431 NETWORK_QUORUM = beast::lexicalCastThrow<std::size_t>(strTemp);
434 FEE_ACCOUNT_RESERVE = beast::lexicalCastThrow<std::uint64_t>(strTemp);
437 FEE_OWNER_RESERVE = beast::lexicalCastThrow<std::uint64_t>(strTemp);
440 FEE_DEFAULT = beast::lexicalCastThrow<std::uint64_t>(strTemp);
444 if (boost::iequals(strTemp,
"full"))
445 LEDGER_HISTORY = 1000000000u;
446 else if (boost::iequals(strTemp,
"none"))
449 LEDGER_HISTORY = beast::lexicalCastThrow<std::uint32_t>(strTemp);
454 if (boost::iequals(strTemp,
"none"))
456 else if (boost::iequals(strTemp,
"full"))
457 FETCH_DEPTH = 1000000000u;
459 FETCH_DEPTH = beast::lexicalCastThrow<std::uint32_t>(strTemp);
461 if (FETCH_DEPTH < 10)
466 PATH_SEARCH_OLD = beast::lexicalCastThrow<int>(strTemp);
468 PATH_SEARCH = beast::lexicalCastThrow<int>(strTemp);
470 PATH_SEARCH_FAST = beast::lexicalCastThrow<int>(strTemp);
472 PATH_SEARCH_MAX = beast::lexicalCastThrow<int>(strTemp);
475 DEBUG_LOGFILE = strTemp;
478 WORKERS = beast::lexicalCastThrow<std::size_t>(strTemp);
481 COMPRESSION = beast::lexicalCastThrow<bool>(strTemp);
494 boost::filesystem::path validatorsFile;
498 validatorsFile = strTemp;
500 if (validatorsFile.empty())
501 Throw<std::runtime_error>(
502 "Invalid path specified in [" SECTION_VALIDATORS_FILE
"]");
504 if (!validatorsFile.is_absolute() && !CONFIG_DIR.empty())
505 validatorsFile = CONFIG_DIR / validatorsFile;
507 if (!boost::filesystem::exists(validatorsFile))
508 Throw<std::runtime_error>(
509 "The file specified in [" SECTION_VALIDATORS_FILE
512 validatorsFile.string());
515 !boost::filesystem::is_regular_file(validatorsFile) &&
516 !boost::filesystem::is_symlink(validatorsFile))
517 Throw<std::runtime_error>(
518 "Invalid file specified in [" SECTION_VALIDATORS_FILE
520 validatorsFile.string());
522 else if (!CONFIG_DIR.empty())
524 validatorsFile = CONFIG_DIR / validatorsFileName;
526 if (!validatorsFile.empty())
528 if (!boost::filesystem::exists(validatorsFile))
529 validatorsFile.clear();
531 !boost::filesystem::is_regular_file(validatorsFile) &&
532 !boost::filesystem::is_symlink(validatorsFile))
533 validatorsFile.clear();
537 if (!validatorsFile.empty() &&
538 boost::filesystem::exists(validatorsFile) &&
539 (boost::filesystem::is_regular_file(validatorsFile) ||
540 boost::filesystem::is_symlink(validatorsFile)))
542 boost::system::error_code ec;
546 Throw<std::runtime_error>(
547 "Failed to read '" + validatorsFile.string() +
"'." +
556 section(SECTION_VALIDATORS).append(*entries);
562 section(SECTION_VALIDATOR_KEYS).append(*valKeyEntries);
564 auto valSiteEntries =
568 section(SECTION_VALIDATOR_LIST_SITES).append(*valSiteEntries);
574 section(SECTION_VALIDATOR_LIST_KEYS).append(*valListKeys);
576 if (!entries && !valKeyEntries && !valListKeys)
577 Throw<std::runtime_error>(
578 "The file specified in [" SECTION_VALIDATORS_FILE
580 "does not contain a [" SECTION_VALIDATORS
582 "[" SECTION_VALIDATOR_KEYS
584 "[" SECTION_VALIDATOR_LIST_KEYS
587 validatorsFile.string());
591 section(SECTION_VALIDATORS)
592 .append(section(SECTION_VALIDATOR_KEYS).lines());
594 if (!section(SECTION_VALIDATOR_LIST_SITES).lines().empty() &&
595 section(SECTION_VALIDATOR_LIST_KEYS).lines().empty())
597 Throw<std::runtime_error>(
599 "] config section is missing");
604 auto const part = section(
"features");
605 for (
auto const& s : part.values())
610 Throw<std::runtime_error>(
611 "Unknown feature: " + s +
" in config file.");
625 if (NETWORK_QUORUM > pm)
627 Throw<std::runtime_error>(
628 "The minimum number of required peers (network_quorum) exceeds "
629 "the maximum number of allowed peers (peers_max)");
634 boost::filesystem::path
635 Config::getDebugLogFile()
const
637 auto log_file = DEBUG_LOGFILE;
639 if (!log_file.empty() && !log_file.is_absolute())
643 log_file = boost::filesystem::absolute(log_file, CONFIG_DIR);
646 if (!log_file.empty())
648 auto log_dir = log_file.parent_path();
650 if (!boost::filesystem::is_directory(log_dir))
652 boost::system::error_code ec;
653 boost::filesystem::create_directories(log_dir, ec);
659 std::cerr <<
"Unable to create log file path " << log_dir
660 <<
": " << ec.message() <<
'\n';
669 Config::getValueFor(
SizedItem item, boost::optional<std::size_t> node)
const
673 assert(!node || *node <= 4);
674 return sizedItems.at(index).second.at(node.value_or(NODE_SIZE));