rippled
Config.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/FileUtilities.h>
21 #include <ripple/basics/Log.h>
22 #include <ripple/basics/StringUtilities.h>
23 #include <ripple/basics/contract.h>
24 #include <ripple/beast/core/LexicalCast.h>
25 #include <ripple/core/Config.h>
26 #include <ripple/core/ConfigSections.h>
27 #include <ripple/json/json_reader.h>
28 #include <ripple/net/HTTPClient.h>
29 #include <ripple/protocol/Feature.h>
30 #include <ripple/protocol/SystemParameters.h>
31 #include <boost/algorithm/string.hpp>
32 #include <boost/format.hpp>
33 #include <boost/predef.h>
34 #include <boost/regex.hpp>
35 #include <boost/system/error_code.hpp>
36 #include <algorithm>
37 #include <cstdlib>
38 #include <iostream>
39 #include <iterator>
40 #include <regex>
41 #include <thread>
42 
43 #if BOOST_OS_WINDOWS
44 #include <sysinfoapi.h>
45 
46 namespace ripple {
47 namespace detail {
48 
49 [[nodiscard]] std::uint64_t
50 getMemorySize()
51 {
52  if (MEMORYSTATUSEX msx{sizeof(MEMORYSTATUSEX)}; GlobalMemoryStatusEx(&msx))
53  return static_cast<std::uint64_t>(msx.ullTotalPhys);
54 
55  return 0;
56 }
57 
58 } // namespace detail
59 } // namespace ripple
60 #endif
61 
62 #if BOOST_OS_LINUX
63 #include <sys/sysinfo.h>
64 
65 namespace ripple {
66 namespace detail {
67 
68 [[nodiscard]] std::uint64_t
69 getMemorySize()
70 {
71  struct sysinfo si;
72 
73  if (sysinfo(&si) == 0)
74  return static_cast<std::uint64_t>(si.totalram);
75 
76  return 0;
77 }
78 
79 } // namespace detail
80 } // namespace ripple
81 
82 #endif
83 
84 #if BOOST_OS_MACOS
85 #include <sys/sysctl.h>
86 #include <sys/types.h>
87 
88 namespace ripple {
89 namespace detail {
90 
91 [[nodiscard]] std::uint64_t
92 getMemorySize()
93 {
94  int mib[] = {CTL_HW, HW_MEMSIZE};
95  std::int64_t ram = 0;
96  size_t size = sizeof(ram);
97 
98  if (sysctl(mib, 2, &ram, &size, NULL, 0) == 0)
99  return static_cast<std::uint64_t>(ram);
100 
101  return 0;
102 }
103 
104 } // namespace detail
105 } // namespace ripple
106 #endif
107 
108 namespace ripple {
109 
110 // clang-format off
111 // The configurable node sizes are "tiny", "small", "medium", "large", "huge"
114 {{
115  // FIXME: We should document each of these items, explaining exactly
116  // what they control and whether there exists an explicit
117  // config option that can be used to override the default.
118 
119  // tiny small medium large huge
120  {SizedItem::sweepInterval, {{ 10, 30, 60, 90, 120 }}},
121  {SizedItem::treeCacheSize, {{ 262144, 524288, 2097152, 4194304, 8388608 }}},
122  {SizedItem::treeCacheAge, {{ 30, 60, 90, 120, 900 }}},
123  {SizedItem::ledgerSize, {{ 32, 32, 64, 256, 384 }}},
124  {SizedItem::ledgerAge, {{ 30, 60, 180, 300, 600 }}},
125  {SizedItem::ledgerFetch, {{ 2, 3, 4, 5, 8 }}},
126  {SizedItem::hashNodeDBCache, {{ 4, 12, 24, 64, 128 }}},
127  {SizedItem::txnDBCache, {{ 4, 12, 24, 64, 128 }}},
128  {SizedItem::lgrDBCache, {{ 4, 8, 16, 32, 128 }}},
129  {SizedItem::openFinalLimit, {{ 8, 16, 32, 64, 128 }}},
130  {SizedItem::burstSize, {{ 4, 8, 16, 32, 48 }}},
131  {SizedItem::ramSizeGB, {{ 8, 12, 16, 24, 32 }}},
132  {SizedItem::accountIdCacheSize, {{ 20047, 50053, 77081, 150061, 300007 }}}
133 }};
134 
135 // Ensure that the order of entries in the table corresponds to the
136 // order of entries in the enum:
137 static_assert(
138  []() constexpr->bool {
139  std::underlying_type_t<SizedItem> idx = 0;
140 
141  for (auto const& i : sizedItems)
142  {
143  if (static_cast<std::underlying_type_t<SizedItem>>(i.first) != idx)
144  return false;
145 
146  ++idx;
147  }
148 
149  return true;
150  }(),
151  "Mismatch between sized item enum & array indices");
152 // clang-format on
153 
154 //
155 // TODO: Check permissions on config file before using it.
156 //
157 
158 #define SECTION_DEFAULT_NAME ""
159 
161 parseIniFile(std::string const& strInput, const bool bTrim)
162 {
163  std::string strData(strInput);
165  IniFileSections secResult;
166 
167  // Convert DOS format to unix.
168  boost::algorithm::replace_all(strData, "\r\n", "\n");
169 
170  // Convert MacOS format to unix.
171  boost::algorithm::replace_all(strData, "\r", "\n");
172 
173  boost::algorithm::split(vLines, strData, boost::algorithm::is_any_of("\n"));
174 
175  // Set the default Section name.
176  std::string strSection = SECTION_DEFAULT_NAME;
177 
178  // Initialize the default Section.
179  secResult[strSection] = IniFileSections::mapped_type();
180 
181  // Parse each line.
182  for (auto& strValue : vLines)
183  {
184  if (bTrim)
185  boost::algorithm::trim(strValue);
186 
187  if (strValue.empty() || strValue[0] == '#')
188  {
189  // Blank line or comment, do nothing.
190  }
191  else if (strValue[0] == '[' && strValue[strValue.length() - 1] == ']')
192  {
193  // New Section.
194  strSection = strValue.substr(1, strValue.length() - 2);
195  secResult.emplace(strSection, IniFileSections::mapped_type{});
196  }
197  else
198  {
199  // Another line for Section.
200  if (!strValue.empty())
201  secResult[strSection].push_back(strValue);
202  }
203  }
204 
205  return secResult;
206 }
207 
208 IniFileSections::mapped_type*
209 getIniFileSection(IniFileSections& secSource, std::string const& strSection)
210 {
211  IniFileSections::iterator it;
212  IniFileSections::mapped_type* smtResult;
213  it = secSource.find(strSection);
214  if (it == secSource.end())
215  smtResult = nullptr;
216  else
217  smtResult = &(it->second);
218  return smtResult;
219 }
220 
221 bool
223  IniFileSections& secSource,
224  std::string const& strSection,
225  std::string& strValue,
226  beast::Journal j)
227 {
228  IniFileSections::mapped_type* pmtEntries =
229  getIniFileSection(secSource, strSection);
230  bool bSingle = pmtEntries && 1 == pmtEntries->size();
231 
232  if (bSingle)
233  {
234  strValue = (*pmtEntries)[0];
235  }
236  else if (pmtEntries)
237  {
238  JLOG(j.warn()) << boost::str(
239  boost::format("Section [%s]: requires 1 line not %d lines.") %
240  strSection % pmtEntries->size());
241  }
242 
243  return bSingle;
244 }
245 
246 //------------------------------------------------------------------------------
247 //
248 // Config (DEPRECATED)
249 //
250 //------------------------------------------------------------------------------
251 
252 char const* const Config::configFileName = "rippled.cfg";
253 char const* const Config::databaseDirName = "db";
254 char const* const Config::validatorsFileName = "validators.txt";
255 
256 [[nodiscard]] static std::string
257 getEnvVar(char const* name)
258 {
259  std::string value;
260 
261  if (auto const v = std::getenv(name); v != nullptr)
262  value = v;
263 
264  return value;
265 }
266 
267 Config::Config()
268  : j_(beast::Journal::getNullSink()), ramSize_(detail::getMemorySize())
269 {
270 }
271 
272 void
273 Config::setupControl(bool bQuiet, bool bSilent, bool bStandalone)
274 {
275  assert(NODE_SIZE == 0);
276 
277  QUIET = bQuiet || bSilent;
278  SILENT = bSilent;
279  RUN_STANDALONE = bStandalone;
280 
281  // We try to autodetect the appropriate node size by checking available
282  // RAM and CPU resources. We default to "tiny" for standalone mode.
283  if (!bStandalone)
284  {
285  // First, check against 'minimum' RAM requirements per node size:
286  auto const& threshold =
288 
289  auto ns = std::find_if(
290  threshold.second.begin(),
291  threshold.second.end(),
292  [this](std::size_t limit) {
293  return (ramSize_ / (1024 * 1024 * 1024)) < limit;
294  });
295 
296  if (ns != threshold.second.end())
297  NODE_SIZE = std::distance(threshold.second.begin(), ns);
298 
299  // Adjust the size based on the number of hardware threads of
300  // execution available to us:
301  if (auto const hc = std::thread::hardware_concurrency())
302  {
303  if (hc == 1)
304  NODE_SIZE = 0;
305 
306  if (hc < 4)
307  NODE_SIZE = std::min<std::size_t>(NODE_SIZE, 1);
308  }
309  }
310 
311  assert(NODE_SIZE <= 4);
312 }
313 
314 void
316  std::string const& strConf,
317  bool bQuiet,
318  bool bSilent,
319  bool bStandalone)
320 {
321  boost::filesystem::path dataDir;
322  std::string strDbPath, strConfFile;
323 
324  // Determine the config and data directories.
325  // If the config file is found in the current working
326  // directory, use the current working directory as the
327  // config directory and that with "db" as the data
328  // directory.
329 
330  setupControl(bQuiet, bSilent, bStandalone);
331 
332  strDbPath = databaseDirName;
333 
334  if (!strConf.empty())
335  strConfFile = strConf;
336  else
337  strConfFile = configFileName;
338 
339  if (!strConf.empty())
340  {
341  // --conf=<path> : everything is relative that file.
342  CONFIG_FILE = strConfFile;
343  CONFIG_DIR = boost::filesystem::absolute(CONFIG_FILE);
344  CONFIG_DIR.remove_filename();
345  dataDir = CONFIG_DIR / strDbPath;
346  }
347  else
348  {
349  CONFIG_DIR = boost::filesystem::current_path();
350  CONFIG_FILE = CONFIG_DIR / strConfFile;
351  dataDir = CONFIG_DIR / strDbPath;
352 
353  // Construct XDG config and data home.
354  // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
355  auto const strHome = getEnvVar("HOME");
356  auto strXdgConfigHome = getEnvVar("XDG_CONFIG_HOME");
357  auto strXdgDataHome = getEnvVar("XDG_DATA_HOME");
358 
359  if (boost::filesystem::exists(CONFIG_FILE)
360  // Can we figure out XDG dirs?
361  || (strHome.empty() &&
362  (strXdgConfigHome.empty() || strXdgDataHome.empty())))
363  {
364  // Current working directory is fine, put dbs in a subdir.
365  }
366  else
367  {
368  if (strXdgConfigHome.empty())
369  {
370  // $XDG_CONFIG_HOME was not set, use default based on $HOME.
371  strXdgConfigHome = strHome + "/.config";
372  }
373 
374  if (strXdgDataHome.empty())
375  {
376  // $XDG_DATA_HOME was not set, use default based on $HOME.
377  strXdgDataHome = strHome + "/.local/share";
378  }
379 
380  CONFIG_DIR = strXdgConfigHome + "/" + systemName();
381  CONFIG_FILE = CONFIG_DIR / strConfFile;
382  dataDir = strXdgDataHome + "/" + systemName();
383 
384  if (!boost::filesystem::exists(CONFIG_FILE))
385  {
386  CONFIG_DIR = "/etc/opt/" + systemName();
387  CONFIG_FILE = CONFIG_DIR / strConfFile;
388  dataDir = "/var/opt/" + systemName();
389  }
390  }
391  }
392 
393  // Update default values
394  load();
395  if (exists("reporting"))
396  {
397  RUN_REPORTING = true;
398  RUN_STANDALONE = true;
399  }
400  {
401  // load() may have set a new value for the dataDir
402  std::string const dbPath(legacy("database_path"));
403  if (!dbPath.empty())
404  dataDir = boost::filesystem::path(dbPath);
405  else if (RUN_STANDALONE)
406  dataDir.clear();
407  }
408 
409  if (!dataDir.empty())
410  {
411  boost::system::error_code ec;
412  boost::filesystem::create_directories(dataDir, ec);
413 
414  if (ec)
415  Throw<std::runtime_error>(
416  boost::str(boost::format("Can not create %s") % dataDir));
417 
418  legacy("database_path", boost::filesystem::absolute(dataDir).string());
419  }
420 
422 
423  if (RUN_STANDALONE)
424  LEDGER_HISTORY = 0;
425 
426  std::string ledgerTxDbType;
427  Section ledgerTxTablesSection = section("ledger_tx_tables");
428  get_if_exists(ledgerTxTablesSection, "use_tx_tables", USE_TX_TABLES);
429 
430  Section& nodeDbSection{section(ConfigSection::nodeDatabase())};
431  get_if_exists(nodeDbSection, "fast_load", FAST_LOAD);
432 }
433 
434 void
436 {
437  // NOTE: this writes to cerr because we want cout to be reserved
438  // for the writing of the json response (so that stdout can be part of a
439  // pipeline, for instance)
440  if (!QUIET)
441  std::cerr << "Loading: " << CONFIG_FILE << "\n";
442 
443  boost::system::error_code ec;
444  auto const fileContents = getFileContents(ec, CONFIG_FILE);
445 
446  if (ec)
447  {
448  std::cerr << "Failed to read '" << CONFIG_FILE << "'." << ec.value()
449  << ": " << ec.message() << std::endl;
450  return;
451  }
452 
453  loadFromString(fileContents);
454 }
455 
456 void
458 {
459  IniFileSections secConfig = parseIniFile(fileContents, true);
460 
461  build(secConfig);
462 
463  if (auto s = getIniFileSection(secConfig, SECTION_IPS))
464  IPS = *s;
465 
466  if (auto s = getIniFileSection(secConfig, SECTION_IPS_FIXED))
467  IPS_FIXED = *s;
468 
469  if (auto s = getIniFileSection(secConfig, SECTION_SNTP))
470  SNTP_SERVERS = *s;
471 
472  // if the user has specified ip:port then replace : with a space.
473  {
474  auto replaceColons = [](std::vector<std::string>& strVec) {
475  const static std::regex e(":([0-9]+)$");
476  for (auto& line : strVec)
477  {
478  // skip anything that might be an ipv6 address
479  if (std::count(line.begin(), line.end(), ':') != 1)
480  continue;
481 
482  std::string result = std::regex_replace(line, e, " $1");
483  // sanity check the result of the replace, should be same length
484  // as input
485  if (result.size() == line.size())
486  line = result;
487  }
488  };
489 
490  replaceColons(IPS_FIXED);
491  replaceColons(IPS);
492  }
493 
494  {
495  std::string dbPath;
496  if (getSingleSection(secConfig, "database_path", dbPath, j_))
497  {
498  boost::filesystem::path p(dbPath);
499  legacy("database_path", boost::filesystem::absolute(p).string());
500  }
501  }
502 
503  std::string strTemp;
504 
505  if (getSingleSection(secConfig, SECTION_PEER_PRIVATE, strTemp, j_))
506  PEER_PRIVATE = beast::lexicalCastThrow<bool>(strTemp);
507 
508  if (getSingleSection(secConfig, SECTION_PEERS_MAX, strTemp, j_))
509  {
510  PEERS_MAX = beast::lexicalCastThrow<std::size_t>(strTemp);
511  }
512  else
513  {
514  std::optional<std::size_t> peers_in_max{};
515  if (getSingleSection(secConfig, SECTION_PEERS_IN_MAX, strTemp, j_))
516  {
517  peers_in_max = beast::lexicalCastThrow<std::size_t>(strTemp);
518  if (*peers_in_max > 1000)
519  Throw<std::runtime_error>(
520  "Invalid value specified in [" SECTION_PEERS_IN_MAX
521  "] section; the value must be less or equal than 1000");
522  }
523 
524  std::optional<std::size_t> peers_out_max{};
525  if (getSingleSection(secConfig, SECTION_PEERS_OUT_MAX, strTemp, j_))
526  {
527  peers_out_max = beast::lexicalCastThrow<std::size_t>(strTemp);
528  if (*peers_out_max < 10 || *peers_out_max > 1000)
529  Throw<std::runtime_error>(
530  "Invalid value specified in [" SECTION_PEERS_OUT_MAX
531  "] section; the value must be in range 10-1000");
532  }
533 
534  // if one section is configured then the other must be configured too
535  if ((peers_in_max && !peers_out_max) ||
536  (peers_out_max && !peers_in_max))
537  Throw<std::runtime_error>("Both sections [" SECTION_PEERS_IN_MAX
538  "]"
539  "and [" SECTION_PEERS_OUT_MAX
540  "] must be configured");
541 
542  if (peers_in_max && peers_out_max)
543  {
544  PEERS_IN_MAX = *peers_in_max;
545  PEERS_OUT_MAX = *peers_out_max;
546  }
547  }
548 
549  if (getSingleSection(secConfig, SECTION_NODE_SIZE, strTemp, j_))
550  {
551  if (boost::iequals(strTemp, "tiny"))
552  NODE_SIZE = 0;
553  else if (boost::iequals(strTemp, "small"))
554  NODE_SIZE = 1;
555  else if (boost::iequals(strTemp, "medium"))
556  NODE_SIZE = 2;
557  else if (boost::iequals(strTemp, "large"))
558  NODE_SIZE = 3;
559  else if (boost::iequals(strTemp, "huge"))
560  NODE_SIZE = 4;
561  else
562  NODE_SIZE = std::min<std::size_t>(
563  4, beast::lexicalCastThrow<std::size_t>(strTemp));
564  }
565 
566  if (getSingleSection(secConfig, SECTION_SIGNING_SUPPORT, strTemp, j_))
567  signingEnabled_ = beast::lexicalCastThrow<bool>(strTemp);
568 
569  if (getSingleSection(secConfig, SECTION_ELB_SUPPORT, strTemp, j_))
570  ELB_SUPPORT = beast::lexicalCastThrow<bool>(strTemp);
571 
572  getSingleSection(secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE, j_);
573  getSingleSection(secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR, j_);
574 
575  if (getSingleSection(secConfig, SECTION_SSL_VERIFY, strTemp, j_))
576  SSL_VERIFY = beast::lexicalCastThrow<bool>(strTemp);
577 
578  if (getSingleSection(secConfig, SECTION_RELAY_VALIDATIONS, strTemp, j_))
579  {
580  if (boost::iequals(strTemp, "all"))
582  else if (boost::iequals(strTemp, "trusted"))
584  else if (boost::iequals(strTemp, "drop_untrusted"))
586  else
587  Throw<std::runtime_error>(
588  "Invalid value specified in [" SECTION_RELAY_VALIDATIONS
589  "] section");
590  }
591 
592  if (getSingleSection(secConfig, SECTION_RELAY_PROPOSALS, strTemp, j_))
593  {
594  if (boost::iequals(strTemp, "all"))
596  else if (boost::iequals(strTemp, "trusted"))
598  else if (boost::iequals(strTemp, "drop_untrusted"))
600  else
601  Throw<std::runtime_error>(
602  "Invalid value specified in [" SECTION_RELAY_PROPOSALS
603  "] section");
604  }
605 
606  if (exists(SECTION_VALIDATION_SEED) && exists(SECTION_VALIDATOR_TOKEN))
607  Throw<std::runtime_error>("Cannot have both [" SECTION_VALIDATION_SEED
608  "] and [" SECTION_VALIDATOR_TOKEN
609  "] config sections");
610 
611  if (getSingleSection(secConfig, SECTION_NETWORK_QUORUM, strTemp, j_))
612  NETWORK_QUORUM = beast::lexicalCastThrow<std::size_t>(strTemp);
613 
614  FEES = setup_FeeVote(section("voting"));
615  /* [fee_default] is documented in the example config files as useful for
616  * things like offline transaction signing. Until that's completely
617  * deprecated, allow it to override the [voting] section. */
618  if (getSingleSection(secConfig, SECTION_FEE_DEFAULT, strTemp, j_))
619  FEES.reference_fee = beast::lexicalCastThrow<std::uint64_t>(strTemp);
620 
621  if (getSingleSection(secConfig, SECTION_LEDGER_HISTORY, strTemp, j_))
622  {
623  if (boost::iequals(strTemp, "full"))
625  std::numeric_limits<decltype(LEDGER_HISTORY)>::max();
626  else if (boost::iequals(strTemp, "none"))
627  LEDGER_HISTORY = 0;
628  else
629  LEDGER_HISTORY = beast::lexicalCastThrow<std::uint32_t>(strTemp);
630  }
631 
632  if (getSingleSection(secConfig, SECTION_FETCH_DEPTH, strTemp, j_))
633  {
634  if (boost::iequals(strTemp, "none"))
635  FETCH_DEPTH = 0;
636  else if (boost::iequals(strTemp, "full"))
637  FETCH_DEPTH = std::numeric_limits<decltype(FETCH_DEPTH)>::max();
638  else
639  FETCH_DEPTH = beast::lexicalCastThrow<std::uint32_t>(strTemp);
640 
641  if (FETCH_DEPTH < 10)
642  FETCH_DEPTH = 10;
643  }
644 
645  // By default, validators don't have pathfinding enabled, unless it is
646  // explicitly requested by the server's admin.
647  if (exists(SECTION_VALIDATION_SEED) || exists(SECTION_VALIDATOR_TOKEN))
648  PATH_SEARCH_MAX = 0;
649 
650  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_OLD, strTemp, j_))
651  PATH_SEARCH_OLD = beast::lexicalCastThrow<int>(strTemp);
652  if (getSingleSection(secConfig, SECTION_PATH_SEARCH, strTemp, j_))
653  PATH_SEARCH = beast::lexicalCastThrow<int>(strTemp);
654  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_FAST, strTemp, j_))
655  PATH_SEARCH_FAST = beast::lexicalCastThrow<int>(strTemp);
656  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_MAX, strTemp, j_))
657  PATH_SEARCH_MAX = beast::lexicalCastThrow<int>(strTemp);
658 
659  if (getSingleSection(secConfig, SECTION_DEBUG_LOGFILE, strTemp, j_))
660  DEBUG_LOGFILE = strTemp;
661 
662  if (getSingleSection(secConfig, SECTION_SWEEP_INTERVAL, strTemp, j_))
663  {
664  SWEEP_INTERVAL = beast::lexicalCastThrow<std::size_t>(strTemp);
665 
666  if (SWEEP_INTERVAL < 10 || SWEEP_INTERVAL > 600)
667  Throw<std::runtime_error>("Invalid " SECTION_SWEEP_INTERVAL
668  ": must be between 10 and 600 inclusive");
669  }
670 
671  if (getSingleSection(secConfig, SECTION_WORKERS, strTemp, j_))
672  {
673  WORKERS = beast::lexicalCastThrow<int>(strTemp);
674 
675  if (WORKERS < 1 || WORKERS > 1024)
676  Throw<std::runtime_error>(
677  "Invalid " SECTION_WORKERS
678  ": must be between 1 and 1024 inclusive.");
679  }
680 
681  if (getSingleSection(secConfig, SECTION_IO_WORKERS, strTemp, j_))
682  {
683  IO_WORKERS = beast::lexicalCastThrow<int>(strTemp);
684 
685  if (IO_WORKERS < 1 || IO_WORKERS > 1024)
686  Throw<std::runtime_error>(
687  "Invalid " SECTION_IO_WORKERS
688  ": must be between 1 and 1024 inclusive.");
689  }
690 
691  if (getSingleSection(secConfig, SECTION_PREFETCH_WORKERS, strTemp, j_))
692  {
693  PREFETCH_WORKERS = beast::lexicalCastThrow<int>(strTemp);
694 
695  if (PREFETCH_WORKERS < 1 || PREFETCH_WORKERS > 1024)
696  Throw<std::runtime_error>(
697  "Invalid " SECTION_PREFETCH_WORKERS
698  ": must be between 1 and 1024 inclusive.");
699  }
700 
701  if (getSingleSection(secConfig, SECTION_COMPRESSION, strTemp, j_))
702  COMPRESSION = beast::lexicalCastThrow<bool>(strTemp);
703 
704  if (getSingleSection(secConfig, SECTION_LEDGER_REPLAY, strTemp, j_))
705  LEDGER_REPLAY = beast::lexicalCastThrow<bool>(strTemp);
706 
707  if (exists(SECTION_REDUCE_RELAY))
708  {
709  auto sec = section(SECTION_REDUCE_RELAY);
710  VP_REDUCE_RELAY_ENABLE = sec.value_or("vp_enable", false);
711  VP_REDUCE_RELAY_SQUELCH = sec.value_or("vp_squelch", false);
712  TX_REDUCE_RELAY_ENABLE = sec.value_or("tx_enable", false);
713  TX_REDUCE_RELAY_METRICS = sec.value_or("tx_metrics", false);
714  TX_REDUCE_RELAY_MIN_PEERS = sec.value_or("tx_min_peers", 20);
715  TX_RELAY_PERCENTAGE = sec.value_or("tx_relay_percentage", 25);
716  if (TX_RELAY_PERCENTAGE < 10 || TX_RELAY_PERCENTAGE > 100 ||
718  Throw<std::runtime_error>(
719  "Invalid " SECTION_REDUCE_RELAY
720  ", tx_min_peers must be greater or equal to 10"
721  ", tx_relay_percentage must be greater or equal to 10 "
722  "and less or equal to 100");
723  }
724 
725  if (getSingleSection(secConfig, SECTION_MAX_TRANSACTIONS, strTemp, j_))
726  {
728  beast::lexicalCastThrow<int>(strTemp),
731  }
732 
733  if (getSingleSection(secConfig, SECTION_SERVER_DOMAIN, strTemp, j_))
734  {
735  if (!isProperlyFormedTomlDomain(strTemp))
736  {
737  Throw<std::runtime_error>(
738  "Invalid " SECTION_SERVER_DOMAIN
739  ": the domain name does not appear to meet the requirements.");
740  }
741 
742  SERVER_DOMAIN = strTemp;
743  }
744 
745  if (exists(SECTION_OVERLAY))
746  {
747  auto const sec = section(SECTION_OVERLAY);
748 
749  using namespace std::chrono;
750 
751  try
752  {
753  if (auto val = sec.get("max_unknown_time"))
755  seconds{beast::lexicalCastThrow<std::uint32_t>(*val)};
756  }
757  catch (...)
758  {
759  Throw<std::runtime_error>(
760  "Invalid value 'max_unknown_time' in " SECTION_OVERLAY
761  ": must be of the form '<number>' representing seconds.");
762  }
763 
764  if (MAX_UNKNOWN_TIME < seconds{300} || MAX_UNKNOWN_TIME > seconds{1800})
765  Throw<std::runtime_error>(
766  "Invalid value 'max_unknown_time' in " SECTION_OVERLAY
767  ": the time must be between 300 and 1800 seconds, inclusive.");
768 
769  try
770  {
771  if (auto val = sec.get("max_diverged_time"))
773  seconds{beast::lexicalCastThrow<std::uint32_t>(*val)};
774  }
775  catch (...)
776  {
777  Throw<std::runtime_error>(
778  "Invalid value 'max_diverged_time' in " SECTION_OVERLAY
779  ": must be of the form '<number>' representing seconds.");
780  }
781 
783  {
784  Throw<std::runtime_error>(
785  "Invalid value 'max_diverged_time' in " SECTION_OVERLAY
786  ": the time must be between 60 and 900 seconds, inclusive.");
787  }
788  }
789 
790  if (getSingleSection(
791  secConfig, SECTION_AMENDMENT_MAJORITY_TIME, strTemp, j_))
792  {
793  using namespace std::chrono;
794  boost::regex const re(
795  "^\\s*(\\d+)\\s*(minutes|hours|days|weeks)\\s*(\\s+.*)?$");
796  boost::smatch match;
797  if (!boost::regex_match(strTemp, match, re))
798  Throw<std::runtime_error>(
799  "Invalid " SECTION_AMENDMENT_MAJORITY_TIME
800  ", must be: [0-9]+ [minutes|hours|days|weeks]");
801 
803  beast::lexicalCastThrow<std::uint32_t>(match[1].str());
804 
805  if (boost::iequals(match[2], "minutes"))
807  else if (boost::iequals(match[2], "hours"))
809  else if (boost::iequals(match[2], "days"))
811  else if (boost::iequals(match[2], "weeks"))
813 
815  Throw<std::runtime_error>(
816  "Invalid " SECTION_AMENDMENT_MAJORITY_TIME
817  ", the minimum amount of time an amendment must hold a "
818  "majority is 15 minutes");
819  }
820 
821  if (getSingleSection(secConfig, SECTION_BETA_RPC_API, strTemp, j_))
822  BETA_RPC_API = beast::lexicalCastThrow<bool>(strTemp);
823 
824  // Do not load trusted validator configuration for standalone mode
825  if (!RUN_STANDALONE)
826  {
827  // If a file was explicitly specified, then throw if the
828  // path is malformed or if the file does not exist or is
829  // not a file.
830  // If the specified file is not an absolute path, then look
831  // for it in the same directory as the config file.
832  // If no path was specified, then look for validators.txt
833  // in the same directory as the config file, but don't complain
834  // if we can't find it.
835  boost::filesystem::path validatorsFile;
836 
837  if (getSingleSection(secConfig, SECTION_VALIDATORS_FILE, strTemp, j_))
838  {
839  validatorsFile = strTemp;
840 
841  if (validatorsFile.empty())
842  Throw<std::runtime_error>(
843  "Invalid path specified in [" SECTION_VALIDATORS_FILE "]");
844 
845  if (!validatorsFile.is_absolute() && !CONFIG_DIR.empty())
846  validatorsFile = CONFIG_DIR / validatorsFile;
847 
848  if (!boost::filesystem::exists(validatorsFile))
849  Throw<std::runtime_error>(
850  "The file specified in [" SECTION_VALIDATORS_FILE
851  "] "
852  "does not exist: " +
853  validatorsFile.string());
854 
855  else if (
856  !boost::filesystem::is_regular_file(validatorsFile) &&
857  !boost::filesystem::is_symlink(validatorsFile))
858  Throw<std::runtime_error>(
859  "Invalid file specified in [" SECTION_VALIDATORS_FILE
860  "]: " +
861  validatorsFile.string());
862  }
863  else if (!CONFIG_DIR.empty())
864  {
865  validatorsFile = CONFIG_DIR / validatorsFileName;
866 
867  if (!validatorsFile.empty())
868  {
869  if (!boost::filesystem::exists(validatorsFile))
870  validatorsFile.clear();
871  else if (
872  !boost::filesystem::is_regular_file(validatorsFile) &&
873  !boost::filesystem::is_symlink(validatorsFile))
874  validatorsFile.clear();
875  }
876  }
877 
878  if (!validatorsFile.empty() &&
879  boost::filesystem::exists(validatorsFile) &&
880  (boost::filesystem::is_regular_file(validatorsFile) ||
881  boost::filesystem::is_symlink(validatorsFile)))
882  {
883  boost::system::error_code ec;
884  auto const data = getFileContents(ec, validatorsFile);
885  if (ec)
886  {
887  Throw<std::runtime_error>(
888  "Failed to read '" + validatorsFile.string() + "'." +
889  std::to_string(ec.value()) + ": " + ec.message());
890  }
891 
892  auto iniFile = parseIniFile(data, true);
893 
894  auto entries = getIniFileSection(iniFile, SECTION_VALIDATORS);
895 
896  if (entries)
897  section(SECTION_VALIDATORS).append(*entries);
898 
899  auto valKeyEntries =
900  getIniFileSection(iniFile, SECTION_VALIDATOR_KEYS);
901 
902  if (valKeyEntries)
903  section(SECTION_VALIDATOR_KEYS).append(*valKeyEntries);
904 
905  auto valSiteEntries =
906  getIniFileSection(iniFile, SECTION_VALIDATOR_LIST_SITES);
907 
908  if (valSiteEntries)
909  section(SECTION_VALIDATOR_LIST_SITES).append(*valSiteEntries);
910 
911  auto valListKeys =
912  getIniFileSection(iniFile, SECTION_VALIDATOR_LIST_KEYS);
913 
914  if (valListKeys)
915  section(SECTION_VALIDATOR_LIST_KEYS).append(*valListKeys);
916 
917  if (!entries && !valKeyEntries && !valListKeys)
918  Throw<std::runtime_error>(
919  "The file specified in [" SECTION_VALIDATORS_FILE
920  "] "
921  "does not contain a [" SECTION_VALIDATORS
922  "], "
923  "[" SECTION_VALIDATOR_KEYS
924  "] or "
925  "[" SECTION_VALIDATOR_LIST_KEYS
926  "]"
927  " section: " +
928  validatorsFile.string());
929  }
930 
931  // Consolidate [validator_keys] and [validators]
932  section(SECTION_VALIDATORS)
933  .append(section(SECTION_VALIDATOR_KEYS).lines());
934 
935  if (!section(SECTION_VALIDATOR_LIST_SITES).lines().empty() &&
936  section(SECTION_VALIDATOR_LIST_KEYS).lines().empty())
937  {
938  Throw<std::runtime_error>(
939  "[" + std::string(SECTION_VALIDATOR_LIST_KEYS) +
940  "] config section is missing");
941  }
942  }
943 
944  {
945  auto const part = section("features");
946  for (auto const& s : part.values())
947  {
948  if (auto const f = getRegisteredFeature(s))
949  features.insert(*f);
950  else
951  Throw<std::runtime_error>(
952  "Unknown feature: " + s + " in config file.");
953  }
954  }
955 
956  // This doesn't properly belong here, but check to make sure that the
957  // value specified for network_quorum is achievable:
958  {
959  auto pm = PEERS_MAX;
960 
961  // FIXME this apparently magic value is actually defined as a constant
962  // elsewhere (see defaultMaxPeers) but we handle this check here.
963  if (pm == 0)
964  pm = 21;
965 
966  if (NETWORK_QUORUM > pm)
967  {
968  Throw<std::runtime_error>(
969  "The minimum number of required peers (network_quorum) exceeds "
970  "the maximum number of allowed peers (peers_max)");
971  }
972  }
973 }
974 
975 boost::filesystem::path
977 {
978  auto log_file = DEBUG_LOGFILE;
979 
980  if (!log_file.empty() && !log_file.is_absolute())
981  {
982  // Unless an absolute path for the log file is specified, the
983  // path is relative to the config file directory.
984  log_file = boost::filesystem::absolute(log_file, CONFIG_DIR);
985  }
986 
987  if (!log_file.empty())
988  {
989  auto log_dir = log_file.parent_path();
990 
991  if (!boost::filesystem::is_directory(log_dir))
992  {
993  boost::system::error_code ec;
994  boost::filesystem::create_directories(log_dir, ec);
995 
996  // If we fail, we warn but continue so that the calling code can
997  // decide how to handle this situation.
998  if (ec)
999  {
1000  std::cerr << "Unable to create log file path " << log_dir
1001  << ": " << ec.message() << '\n';
1002  }
1003  }
1004  }
1005 
1006  return log_file;
1007 }
1008 
1009 int
1011 {
1012  auto const index = static_cast<std::underlying_type_t<SizedItem>>(item);
1013  assert(index < sizedItems.size());
1014  assert(!node || *node <= 4);
1015  return sizedItems.at(index).second.at(node.value_or(NODE_SIZE));
1016 }
1017 
1018 FeeSetup
1020 {
1021  FeeSetup setup;
1022  {
1023  std::uint64_t temp;
1024  if (set(temp, "reference_fee", section) &&
1026  setup.reference_fee = temp;
1027  }
1028  {
1029  std::uint32_t temp;
1030  if (set(temp, "account_reserve", section))
1031  setup.account_reserve = temp;
1032  if (set(temp, "owner_reserve", section))
1033  setup.owner_reserve = temp;
1034  }
1035  return setup;
1036 }
1037 
1038 } // namespace ripple
ripple::SizedItem::openFinalLimit
@ openFinalLimit
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:42
ripple::FeeSetup::reference_fee
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition: Config.h:72
ripple::Config::SWEEP_INTERVAL
std::optional< int > SWEEP_INTERVAL
Definition: Config.h:247
ripple::getFileContents
std::string getFileContents(boost::system::error_code &ec, boost::filesystem::path const &sourcePath, std::optional< std::size_t > maxSize=std::nullopt)
Definition: FileUtilities.cpp:25
regex
std::string
STL class.
ripple::SizedItem
SizedItem
Definition: Config.h:48
ripple::Config::PATH_SEARCH
int PATH_SEARCH
Definition: Config.h:200
ripple::Config::LEDGER_REPLAY
bool LEDGER_REPLAY
Definition: Config.h:227
ripple::SizedItem::accountIdCacheSize
@ accountIdCacheSize
ripple::Config::validatorsFileName
static char const *const validatorsFileName
Definition: Config.h:95
std::vector< std::string >
std::map::find
T find(T... args)
std::size
T size(T... args)
ripple::Config::SSL_VERIFY_DIR
std::string SSL_VERIFY_DIR
Definition: Config.h:221
std::optional::value_or
T value_or(T... args)
ripple::Config::CONFIG_FILE
boost::filesystem::path CONFIG_FILE
Definition: Config.h:102
std::chrono::seconds
ripple::Config::NODE_SIZE
std::size_t NODE_SIZE
Definition: Config.h:217
iterator
ripple::Config::PEER_PRIVATE
bool PEER_PRIVATE
Definition: Config.h:177
ripple::Config::DEBUG_LOGFILE
boost::filesystem::path DEBUG_LOGFILE
Definition: Config.h:108
std::map::emplace
T emplace(T... args)
ripple::Config::setupControl
void setupControl(bool bQuiet, bool bSilent, bool bStandalone)
Definition: Config.cpp:273
ripple::SizedItem::treeCacheAge
@ treeCacheAge
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
std::distance
T distance(T... args)
std::cerr
ripple::SizedItem::hashNodeDBCache
@ hashNodeDBCache
ripple::Config::MIN_JOB_QUEUE_TX
static constexpr int MIN_JOB_QUEUE_TX
Definition: Config.h:232
iostream
ripple::SizedItem::ledgerFetch
@ ledgerFetch
ripple::Config::MAX_TRANSACTIONS
int MAX_TRANSACTIONS
Definition: Config.h:230
ripple::Config::FETCH_DEPTH
std::uint32_t FETCH_DEPTH
Definition: Config.h:212
algorithm
ripple::Config::PATH_SEARCH_MAX
int PATH_SEARCH_MAX
Definition: Config.h:202
ripple::Config::VP_REDUCE_RELAY_SQUELCH
bool VP_REDUCE_RELAY_SQUELCH
Definition: Config.h:261
ripple::get_if_exists
bool get_if_exists(Section const &section, std::string const &name, T &v)
Definition: BasicConfig.h:384
ripple::Config::IO_WORKERS
int IO_WORKERS
Definition: Config.h:239
ripple::Section::append
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
Definition: BasicConfig.cpp:38
std::underlying_type_t
ripple::Config::RUN_STANDALONE
bool RUN_STANDALONE
Operate in stand-alone mode.
Definition: Config.h:125
ripple::SizedItem::ramSizeGB
@ ramSizeGB
ripple::Config::load
void load()
Definition: Config.cpp:435
ripple::Config::j_
const beast::Journal j_
Definition: Config.h:112
ripple::Config::RELAY_UNTRUSTED_PROPOSALS
int RELAY_UNTRUSTED_PROPOSALS
Definition: Config.h:174
ripple::Config::SSL_VERIFY_FILE
std::string SSL_VERIFY_FILE
Definition: Config.h:220
ripple::Config::loadFromString
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition: Config.cpp:457
ripple::Config::getValueFor
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.
Definition: Config.cpp:1010
ripple::weeks
std::chrono::duration< int, std::ratio_multiply< days::period, std::ratio< 7 > >> weeks
Definition: chrono.h:41
thread
ripple::Config::FAST_LOAD
bool FAST_LOAD
Definition: Config.h:295
std::thread::hardware_concurrency
T hardware_concurrency(T... args)
ripple::Config::SNTP_SERVERS
std::vector< std::string > SNTP_SERVERS
Definition: Config.h:151
ripple::Config::IPS_FIXED
std::vector< std::string > IPS_FIXED
Definition: Config.h:150
ripple::Config::SSL_VERIFY
bool SSL_VERIFY
Definition: Config.h:219
ripple::BasicConfig::build
void build(IniFileSections const &ifs)
Definition: BasicConfig.cpp:176
ripple::Config::USE_TX_TABLES
bool USE_TX_TABLES
Definition: Config.h:131
std::getenv
T getenv(T... args)
std::to_string
T to_string(T... args)
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:313
std::array
STL class.
ripple::Config::BETA_RPC_API
bool BETA_RPC_API
Definition: Config.h:292
ripple::BasicConfig::legacy
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Definition: BasicConfig.cpp:164
ripple::setup_FeeVote
FeeSetup setup_FeeVote(Section const &section)
Definition: Config.cpp:1019
ripple::Config::PEERS_OUT_MAX
std::size_t PEERS_OUT_MAX
Definition: Config.h:184
ripple::Config::AMENDMENT_MAJORITY_TIME
std::chrono::seconds AMENDMENT_MAJORITY_TIME
Definition: Config.h:235
ripple::SizedItem::lgrDBCache
@ lgrDBCache
ripple::Config::MAX_JOB_QUEUE_TX
static constexpr int MAX_JOB_QUEUE_TX
Definition: Config.h:231
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::SizedItem::burstSize
@ burstSize
std::uint64_t
ripple::Config::WORKERS
int WORKERS
Definition: Config.h:238
ripple::Config::PEERS_IN_MAX
std::size_t PEERS_IN_MAX
Definition: Config.h:185
ripple::Config::databaseDirName
static char const *const databaseDirName
Definition: Config.h:94
std::map
STL class.
std::regex
ripple::SizedItem::txnDBCache
@ txnDBCache
ripple::Config::PREFETCH_WORKERS
int PREFETCH_WORKERS
Definition: Config.h:240
ripple::Config::PATH_SEARCH_OLD
int PATH_SEARCH_OLD
Definition: Config.h:199
ripple::Config::LEDGER_HISTORY
std::uint32_t LEDGER_HISTORY
Definition: Config.h:211
ripple::parseIniFile
IniFileSections parseIniFile(std::string const &strInput, const bool bTrim)
Definition: Config.cpp:161
ripple::Config::NETWORK_QUORUM
std::size_t NETWORK_QUORUM
Definition: Config.h:168
ripple::sizedItems
constexpr std::array< std::pair< SizedItem, std::array< int, 5 > >, 13 > sizedItems
Definition: Config.cpp:114
ripple::Config::VP_REDUCE_RELAY_ENABLE
bool VP_REDUCE_RELAY_ENABLE
Definition: Config.h:252
ripple::Config::CONFIG_DIR
boost::filesystem::path CONFIG_DIR
Definition: Config.h:105
std::string::substr
T substr(T... args)
ripple::Config::PEERS_MAX
std::size_t PEERS_MAX
Definition: Config.h:183
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Config::features
std::unordered_set< uint256, beast::uhash<> > features
Definition: Config.h:281
ripple::Config::PATH_SEARCH_FAST
int PATH_SEARCH_FAST
Definition: Config.h:201
ripple::getSingleSection
bool getSingleSection(IniFileSections &secSource, std::string const &strSection, std::string &strValue, beast::Journal j)
Definition: Config.cpp:222
ripple::Config::setup
void setup(std::string const &strConf, bool bQuiet, bool bSilent, bool bStandalone)
Definition: Config.cpp:315
cstdlib
std::endl
T endl(T... args)
std::clamp
T clamp(T... args)
ripple::getEnvVar
static std::string getEnvVar(char const *name)
Definition: Config.cpp:257
ripple::SizedItem::treeCacheSize
@ treeCacheSize
ripple::Config::TX_REDUCE_RELAY_MIN_PEERS
std::size_t TX_REDUCE_RELAY_MIN_PEERS
Definition: Config.h:273
ripple::Config::SERVER_DOMAIN
std::string SERVER_DOMAIN
Definition: Config.h:283
ripple::Config::TX_REDUCE_RELAY_METRICS
bool TX_REDUCE_RELAY_METRICS
Definition: Config.h:270
ripple::Config::RELAY_UNTRUSTED_VALIDATIONS
int RELAY_UNTRUSTED_VALIDATIONS
Definition: Config.h:173
ripple::SizedItem::sweepInterval
@ sweepInterval
ripple::Config::COMPRESSION
bool COMPRESSION
Definition: Config.h:224
std::count
T count(T... args)
std::string::empty
T empty(T... args)
ripple::systemName
static std::string const & systemName()
Definition: SystemParameters.h:34
ripple::SizedItem::ledgerSize
@ ledgerSize
std::optional< std::size_t >
ripple::Config::IPS
std::vector< std::string > IPS
Definition: Config.h:149
ripple::Config::configFileName
static char const *const configFileName
Definition: Config.h:93
std::size_t
ripple::isProperlyFormedTomlDomain
bool isProperlyFormedTomlDomain(std::string const &domain)
Determines if the given string looks like a TOML-file hosting domain.
ripple::Config::TX_RELAY_PERCENTAGE
std::size_t TX_RELAY_PERCENTAGE
Definition: Config.h:276
ripple::FeeSetup
Fee schedule for startup / standalone, and to vote for.
Definition: Config.h:69
std::map::end
T end(T... args)
ripple::Config::QUIET
bool QUIET
Definition: Config.h:114
ripple::days
std::chrono::duration< int, std::ratio_multiply< std::chrono::hours::period, std::ratio< 24 > >> days
Definition: chrono.h:38
ripple::Config::TX_REDUCE_RELAY_ENABLE
bool TX_REDUCE_RELAY_ENABLE
Definition: Config.h:263
ripple::getRegisteredFeature
std::optional< uint256 > getRegisteredFeature(std::string const &name)
Definition: Feature.cpp:342
ripple::Config::SILENT
bool SILENT
Definition: Config.h:115
ripple::Config::getDebugLogFile
boost::filesystem::path getDebugLogFile() const
Returns the full path and filename of the debug log file.
Definition: Config.cpp:976
ripple::Config::FEES
FeeSetup FEES
Definition: Config.h:208
ripple::Config::signingEnabled_
bool signingEnabled_
Determines if the server will sign a tx, given an account's secret seed.
Definition: Config.h:139
std::numeric_limits
std::regex_replace
T regex_replace(T... args)
ripple::Config::ELB_SUPPORT
bool ELB_SUPPORT
Definition: Config.h:147
ripple::HTTPClient::initializeSSLContext
static void initializeSSLContext(Config const &config, beast::Journal j)
Definition: HTTPClient.cpp:38
ripple::ConfigSection::nodeDatabase
static std::string nodeDatabase()
Definition: ConfigSections.h:33
ripple::getIniFileSection
IniFileSections::mapped_type * getIniFileSection(IniFileSections &secSource, std::string const &strSection)
Definition: Config.cpp:209
ripple::BasicConfig::exists
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
Definition: BasicConfig.cpp:121
ripple::SizedItem::ledgerAge
@ ledgerAge
ripple::Config::MAX_UNKNOWN_TIME
std::chrono::seconds MAX_UNKNOWN_TIME
Definition: Config.h:286
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:127
ripple::Config::MAX_DIVERGED_TIME
std::chrono::seconds MAX_DIVERGED_TIME
Definition: Config.h:289
ripple::IniFileSections
std::map< std::string, std::vector< std::string > > IniFileSections
Definition: BasicConfig.h:35
ripple::Config::RUN_REPORTING
bool RUN_REPORTING
Definition: Config.h:127
beast
Definition: base_uint.h:641
std::chrono