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