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_NETWORK_ID, strTemp, j_))
506  {
507  if (strTemp == "main")
508  NETWORK_ID = 0;
509  else if (strTemp == "testnet")
510  NETWORK_ID = 1;
511  else if (strTemp == "devnet")
512  NETWORK_ID = 2;
513  else
514  NETWORK_ID = beast::lexicalCastThrow<uint32_t>(strTemp);
515  }
516 
517  if (getSingleSection(secConfig, SECTION_PEER_PRIVATE, strTemp, j_))
518  PEER_PRIVATE = beast::lexicalCastThrow<bool>(strTemp);
519 
520  if (getSingleSection(secConfig, SECTION_PEERS_MAX, strTemp, j_))
521  {
522  PEERS_MAX = beast::lexicalCastThrow<std::size_t>(strTemp);
523  }
524  else
525  {
526  std::optional<std::size_t> peers_in_max{};
527  if (getSingleSection(secConfig, SECTION_PEERS_IN_MAX, strTemp, j_))
528  {
529  peers_in_max = beast::lexicalCastThrow<std::size_t>(strTemp);
530  if (*peers_in_max > 1000)
531  Throw<std::runtime_error>(
532  "Invalid value specified in [" SECTION_PEERS_IN_MAX
533  "] section; the value must be less or equal than 1000");
534  }
535 
536  std::optional<std::size_t> peers_out_max{};
537  if (getSingleSection(secConfig, SECTION_PEERS_OUT_MAX, strTemp, j_))
538  {
539  peers_out_max = beast::lexicalCastThrow<std::size_t>(strTemp);
540  if (*peers_out_max < 10 || *peers_out_max > 1000)
541  Throw<std::runtime_error>(
542  "Invalid value specified in [" SECTION_PEERS_OUT_MAX
543  "] section; the value must be in range 10-1000");
544  }
545 
546  // if one section is configured then the other must be configured too
547  if ((peers_in_max && !peers_out_max) ||
548  (peers_out_max && !peers_in_max))
549  Throw<std::runtime_error>("Both sections [" SECTION_PEERS_IN_MAX
550  "]"
551  "and [" SECTION_PEERS_OUT_MAX
552  "] must be configured");
553 
554  if (peers_in_max && peers_out_max)
555  {
556  PEERS_IN_MAX = *peers_in_max;
557  PEERS_OUT_MAX = *peers_out_max;
558  }
559  }
560 
561  if (getSingleSection(secConfig, SECTION_NODE_SIZE, strTemp, j_))
562  {
563  if (boost::iequals(strTemp, "tiny"))
564  NODE_SIZE = 0;
565  else if (boost::iequals(strTemp, "small"))
566  NODE_SIZE = 1;
567  else if (boost::iequals(strTemp, "medium"))
568  NODE_SIZE = 2;
569  else if (boost::iequals(strTemp, "large"))
570  NODE_SIZE = 3;
571  else if (boost::iequals(strTemp, "huge"))
572  NODE_SIZE = 4;
573  else
574  NODE_SIZE = std::min<std::size_t>(
575  4, beast::lexicalCastThrow<std::size_t>(strTemp));
576  }
577 
578  if (getSingleSection(secConfig, SECTION_SIGNING_SUPPORT, strTemp, j_))
579  signingEnabled_ = beast::lexicalCastThrow<bool>(strTemp);
580 
581  if (getSingleSection(secConfig, SECTION_ELB_SUPPORT, strTemp, j_))
582  ELB_SUPPORT = beast::lexicalCastThrow<bool>(strTemp);
583 
584  getSingleSection(secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE, j_);
585  getSingleSection(secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR, j_);
586 
587  if (getSingleSection(secConfig, SECTION_SSL_VERIFY, strTemp, j_))
588  SSL_VERIFY = beast::lexicalCastThrow<bool>(strTemp);
589 
590  if (getSingleSection(secConfig, SECTION_RELAY_VALIDATIONS, strTemp, j_))
591  {
592  if (boost::iequals(strTemp, "all"))
594  else if (boost::iequals(strTemp, "trusted"))
596  else if (boost::iequals(strTemp, "drop_untrusted"))
598  else
599  Throw<std::runtime_error>(
600  "Invalid value specified in [" SECTION_RELAY_VALIDATIONS
601  "] section");
602  }
603 
604  if (getSingleSection(secConfig, SECTION_RELAY_PROPOSALS, strTemp, j_))
605  {
606  if (boost::iequals(strTemp, "all"))
608  else if (boost::iequals(strTemp, "trusted"))
610  else if (boost::iequals(strTemp, "drop_untrusted"))
612  else
613  Throw<std::runtime_error>(
614  "Invalid value specified in [" SECTION_RELAY_PROPOSALS
615  "] section");
616  }
617 
618  if (exists(SECTION_VALIDATION_SEED) && exists(SECTION_VALIDATOR_TOKEN))
619  Throw<std::runtime_error>("Cannot have both [" SECTION_VALIDATION_SEED
620  "] and [" SECTION_VALIDATOR_TOKEN
621  "] config sections");
622 
623  if (getSingleSection(secConfig, SECTION_NETWORK_QUORUM, strTemp, j_))
624  NETWORK_QUORUM = beast::lexicalCastThrow<std::size_t>(strTemp);
625 
626  FEES = setup_FeeVote(section("voting"));
627  /* [fee_default] is documented in the example config files as useful for
628  * things like offline transaction signing. Until that's completely
629  * deprecated, allow it to override the [voting] section. */
630  if (getSingleSection(secConfig, SECTION_FEE_DEFAULT, strTemp, j_))
631  FEES.reference_fee = beast::lexicalCastThrow<std::uint64_t>(strTemp);
632 
633  if (getSingleSection(secConfig, SECTION_LEDGER_HISTORY, strTemp, j_))
634  {
635  if (boost::iequals(strTemp, "full"))
637  std::numeric_limits<decltype(LEDGER_HISTORY)>::max();
638  else if (boost::iequals(strTemp, "none"))
639  LEDGER_HISTORY = 0;
640  else
641  LEDGER_HISTORY = beast::lexicalCastThrow<std::uint32_t>(strTemp);
642  }
643 
644  if (getSingleSection(secConfig, SECTION_FETCH_DEPTH, strTemp, j_))
645  {
646  if (boost::iequals(strTemp, "none"))
647  FETCH_DEPTH = 0;
648  else if (boost::iequals(strTemp, "full"))
649  FETCH_DEPTH = std::numeric_limits<decltype(FETCH_DEPTH)>::max();
650  else
651  FETCH_DEPTH = beast::lexicalCastThrow<std::uint32_t>(strTemp);
652 
653  if (FETCH_DEPTH < 10)
654  FETCH_DEPTH = 10;
655  }
656 
657  // By default, validators don't have pathfinding enabled, unless it is
658  // explicitly requested by the server's admin.
659  if (exists(SECTION_VALIDATION_SEED) || exists(SECTION_VALIDATOR_TOKEN))
660  PATH_SEARCH_MAX = 0;
661 
662  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_OLD, strTemp, j_))
663  PATH_SEARCH_OLD = beast::lexicalCastThrow<int>(strTemp);
664  if (getSingleSection(secConfig, SECTION_PATH_SEARCH, strTemp, j_))
665  PATH_SEARCH = beast::lexicalCastThrow<int>(strTemp);
666  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_FAST, strTemp, j_))
667  PATH_SEARCH_FAST = beast::lexicalCastThrow<int>(strTemp);
668  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_MAX, strTemp, j_))
669  PATH_SEARCH_MAX = beast::lexicalCastThrow<int>(strTemp);
670 
671  if (getSingleSection(secConfig, SECTION_DEBUG_LOGFILE, strTemp, j_))
672  DEBUG_LOGFILE = strTemp;
673 
674  if (getSingleSection(secConfig, SECTION_SWEEP_INTERVAL, strTemp, j_))
675  {
676  SWEEP_INTERVAL = beast::lexicalCastThrow<std::size_t>(strTemp);
677 
678  if (SWEEP_INTERVAL < 10 || SWEEP_INTERVAL > 600)
679  Throw<std::runtime_error>("Invalid " SECTION_SWEEP_INTERVAL
680  ": must be between 10 and 600 inclusive");
681  }
682 
683  if (getSingleSection(secConfig, SECTION_WORKERS, strTemp, j_))
684  {
685  WORKERS = beast::lexicalCastThrow<int>(strTemp);
686 
687  if (WORKERS < 1 || WORKERS > 1024)
688  Throw<std::runtime_error>(
689  "Invalid " SECTION_WORKERS
690  ": must be between 1 and 1024 inclusive.");
691  }
692 
693  if (getSingleSection(secConfig, SECTION_IO_WORKERS, strTemp, j_))
694  {
695  IO_WORKERS = beast::lexicalCastThrow<int>(strTemp);
696 
697  if (IO_WORKERS < 1 || IO_WORKERS > 1024)
698  Throw<std::runtime_error>(
699  "Invalid " SECTION_IO_WORKERS
700  ": must be between 1 and 1024 inclusive.");
701  }
702 
703  if (getSingleSection(secConfig, SECTION_PREFETCH_WORKERS, strTemp, j_))
704  {
705  PREFETCH_WORKERS = beast::lexicalCastThrow<int>(strTemp);
706 
707  if (PREFETCH_WORKERS < 1 || PREFETCH_WORKERS > 1024)
708  Throw<std::runtime_error>(
709  "Invalid " SECTION_PREFETCH_WORKERS
710  ": must be between 1 and 1024 inclusive.");
711  }
712 
713  if (getSingleSection(secConfig, SECTION_COMPRESSION, strTemp, j_))
714  COMPRESSION = beast::lexicalCastThrow<bool>(strTemp);
715 
716  if (getSingleSection(secConfig, SECTION_LEDGER_REPLAY, strTemp, j_))
717  LEDGER_REPLAY = beast::lexicalCastThrow<bool>(strTemp);
718 
719  if (exists(SECTION_REDUCE_RELAY))
720  {
721  auto sec = section(SECTION_REDUCE_RELAY);
722  VP_REDUCE_RELAY_ENABLE = sec.value_or("vp_enable", false);
723  VP_REDUCE_RELAY_SQUELCH = sec.value_or("vp_squelch", false);
724  TX_REDUCE_RELAY_ENABLE = sec.value_or("tx_enable", false);
725  TX_REDUCE_RELAY_METRICS = sec.value_or("tx_metrics", false);
726  TX_REDUCE_RELAY_MIN_PEERS = sec.value_or("tx_min_peers", 20);
727  TX_RELAY_PERCENTAGE = sec.value_or("tx_relay_percentage", 25);
728  if (TX_RELAY_PERCENTAGE < 10 || TX_RELAY_PERCENTAGE > 100 ||
730  Throw<std::runtime_error>(
731  "Invalid " SECTION_REDUCE_RELAY
732  ", tx_min_peers must be greater or equal to 10"
733  ", tx_relay_percentage must be greater or equal to 10 "
734  "and less or equal to 100");
735  }
736 
737  if (getSingleSection(secConfig, SECTION_MAX_TRANSACTIONS, strTemp, j_))
738  {
740  beast::lexicalCastThrow<int>(strTemp),
743  }
744 
745  if (getSingleSection(secConfig, SECTION_SERVER_DOMAIN, strTemp, j_))
746  {
747  if (!isProperlyFormedTomlDomain(strTemp))
748  {
749  Throw<std::runtime_error>(
750  "Invalid " SECTION_SERVER_DOMAIN
751  ": the domain name does not appear to meet the requirements.");
752  }
753 
754  SERVER_DOMAIN = strTemp;
755  }
756 
757  if (exists(SECTION_OVERLAY))
758  {
759  auto const sec = section(SECTION_OVERLAY);
760 
761  using namespace std::chrono;
762 
763  try
764  {
765  if (auto val = sec.get("max_unknown_time"))
767  seconds{beast::lexicalCastThrow<std::uint32_t>(*val)};
768  }
769  catch (...)
770  {
771  Throw<std::runtime_error>(
772  "Invalid value 'max_unknown_time' in " SECTION_OVERLAY
773  ": must be of the form '<number>' representing seconds.");
774  }
775 
776  if (MAX_UNKNOWN_TIME < seconds{300} || MAX_UNKNOWN_TIME > seconds{1800})
777  Throw<std::runtime_error>(
778  "Invalid value 'max_unknown_time' in " SECTION_OVERLAY
779  ": the time must be between 300 and 1800 seconds, inclusive.");
780 
781  try
782  {
783  if (auto val = sec.get("max_diverged_time"))
785  seconds{beast::lexicalCastThrow<std::uint32_t>(*val)};
786  }
787  catch (...)
788  {
789  Throw<std::runtime_error>(
790  "Invalid value 'max_diverged_time' in " SECTION_OVERLAY
791  ": must be of the form '<number>' representing seconds.");
792  }
793 
795  {
796  Throw<std::runtime_error>(
797  "Invalid value 'max_diverged_time' in " SECTION_OVERLAY
798  ": the time must be between 60 and 900 seconds, inclusive.");
799  }
800  }
801 
802  if (getSingleSection(
803  secConfig, SECTION_AMENDMENT_MAJORITY_TIME, strTemp, j_))
804  {
805  using namespace std::chrono;
806  boost::regex const re(
807  "^\\s*(\\d+)\\s*(minutes|hours|days|weeks)\\s*(\\s+.*)?$");
808  boost::smatch match;
809  if (!boost::regex_match(strTemp, match, re))
810  Throw<std::runtime_error>(
811  "Invalid " SECTION_AMENDMENT_MAJORITY_TIME
812  ", must be: [0-9]+ [minutes|hours|days|weeks]");
813 
815  beast::lexicalCastThrow<std::uint32_t>(match[1].str());
816 
817  if (boost::iequals(match[2], "minutes"))
819  else if (boost::iequals(match[2], "hours"))
821  else if (boost::iequals(match[2], "days"))
823  else if (boost::iequals(match[2], "weeks"))
825 
827  Throw<std::runtime_error>(
828  "Invalid " SECTION_AMENDMENT_MAJORITY_TIME
829  ", the minimum amount of time an amendment must hold a "
830  "majority is 15 minutes");
831  }
832 
833  if (getSingleSection(secConfig, SECTION_BETA_RPC_API, strTemp, j_))
834  BETA_RPC_API = beast::lexicalCastThrow<bool>(strTemp);
835 
836  // Do not load trusted validator configuration for standalone mode
837  if (!RUN_STANDALONE)
838  {
839  // If a file was explicitly specified, then throw if the
840  // path is malformed or if the file does not exist or is
841  // not a file.
842  // If the specified file is not an absolute path, then look
843  // for it in the same directory as the config file.
844  // If no path was specified, then look for validators.txt
845  // in the same directory as the config file, but don't complain
846  // if we can't find it.
847  boost::filesystem::path validatorsFile;
848 
849  if (getSingleSection(secConfig, SECTION_VALIDATORS_FILE, strTemp, j_))
850  {
851  validatorsFile = strTemp;
852 
853  if (validatorsFile.empty())
854  Throw<std::runtime_error>(
855  "Invalid path specified in [" SECTION_VALIDATORS_FILE "]");
856 
857  if (!validatorsFile.is_absolute() && !CONFIG_DIR.empty())
858  validatorsFile = CONFIG_DIR / validatorsFile;
859 
860  if (!boost::filesystem::exists(validatorsFile))
861  Throw<std::runtime_error>(
862  "The file specified in [" SECTION_VALIDATORS_FILE
863  "] "
864  "does not exist: " +
865  validatorsFile.string());
866 
867  else if (
868  !boost::filesystem::is_regular_file(validatorsFile) &&
869  !boost::filesystem::is_symlink(validatorsFile))
870  Throw<std::runtime_error>(
871  "Invalid file specified in [" SECTION_VALIDATORS_FILE
872  "]: " +
873  validatorsFile.string());
874  }
875  else if (!CONFIG_DIR.empty())
876  {
877  validatorsFile = CONFIG_DIR / validatorsFileName;
878 
879  if (!validatorsFile.empty())
880  {
881  if (!boost::filesystem::exists(validatorsFile))
882  validatorsFile.clear();
883  else if (
884  !boost::filesystem::is_regular_file(validatorsFile) &&
885  !boost::filesystem::is_symlink(validatorsFile))
886  validatorsFile.clear();
887  }
888  }
889 
890  if (!validatorsFile.empty() &&
891  boost::filesystem::exists(validatorsFile) &&
892  (boost::filesystem::is_regular_file(validatorsFile) ||
893  boost::filesystem::is_symlink(validatorsFile)))
894  {
895  boost::system::error_code ec;
896  auto const data = getFileContents(ec, validatorsFile);
897  if (ec)
898  {
899  Throw<std::runtime_error>(
900  "Failed to read '" + validatorsFile.string() + "'." +
901  std::to_string(ec.value()) + ": " + ec.message());
902  }
903 
904  auto iniFile = parseIniFile(data, true);
905 
906  auto entries = getIniFileSection(iniFile, SECTION_VALIDATORS);
907 
908  if (entries)
909  section(SECTION_VALIDATORS).append(*entries);
910 
911  auto valKeyEntries =
912  getIniFileSection(iniFile, SECTION_VALIDATOR_KEYS);
913 
914  if (valKeyEntries)
915  section(SECTION_VALIDATOR_KEYS).append(*valKeyEntries);
916 
917  auto valSiteEntries =
918  getIniFileSection(iniFile, SECTION_VALIDATOR_LIST_SITES);
919 
920  if (valSiteEntries)
921  section(SECTION_VALIDATOR_LIST_SITES).append(*valSiteEntries);
922 
923  auto valListKeys =
924  getIniFileSection(iniFile, SECTION_VALIDATOR_LIST_KEYS);
925 
926  if (valListKeys)
927  section(SECTION_VALIDATOR_LIST_KEYS).append(*valListKeys);
928 
929  if (!entries && !valKeyEntries && !valListKeys)
930  Throw<std::runtime_error>(
931  "The file specified in [" SECTION_VALIDATORS_FILE
932  "] "
933  "does not contain a [" SECTION_VALIDATORS
934  "], "
935  "[" SECTION_VALIDATOR_KEYS
936  "] or "
937  "[" SECTION_VALIDATOR_LIST_KEYS
938  "]"
939  " section: " +
940  validatorsFile.string());
941  }
942 
943  // Consolidate [validator_keys] and [validators]
944  section(SECTION_VALIDATORS)
945  .append(section(SECTION_VALIDATOR_KEYS).lines());
946 
947  if (!section(SECTION_VALIDATOR_LIST_SITES).lines().empty() &&
948  section(SECTION_VALIDATOR_LIST_KEYS).lines().empty())
949  {
950  Throw<std::runtime_error>(
951  "[" + std::string(SECTION_VALIDATOR_LIST_KEYS) +
952  "] config section is missing");
953  }
954  }
955 
956  {
957  auto const part = section("features");
958  for (auto const& s : part.values())
959  {
960  if (auto const f = getRegisteredFeature(s))
961  features.insert(*f);
962  else
963  Throw<std::runtime_error>(
964  "Unknown feature: " + s + " in config file.");
965  }
966  }
967 
968  // This doesn't properly belong here, but check to make sure that the
969  // value specified for network_quorum is achievable:
970  {
971  auto pm = PEERS_MAX;
972 
973  // FIXME this apparently magic value is actually defined as a constant
974  // elsewhere (see defaultMaxPeers) but we handle this check here.
975  if (pm == 0)
976  pm = 21;
977 
978  if (NETWORK_QUORUM > pm)
979  {
980  Throw<std::runtime_error>(
981  "The minimum number of required peers (network_quorum) exceeds "
982  "the maximum number of allowed peers (peers_max)");
983  }
984  }
985 }
986 
987 boost::filesystem::path
989 {
990  auto log_file = DEBUG_LOGFILE;
991 
992  if (!log_file.empty() && !log_file.is_absolute())
993  {
994  // Unless an absolute path for the log file is specified, the
995  // path is relative to the config file directory.
996  log_file = boost::filesystem::absolute(log_file, CONFIG_DIR);
997  }
998 
999  if (!log_file.empty())
1000  {
1001  auto log_dir = log_file.parent_path();
1002 
1003  if (!boost::filesystem::is_directory(log_dir))
1004  {
1005  boost::system::error_code ec;
1006  boost::filesystem::create_directories(log_dir, ec);
1007 
1008  // If we fail, we warn but continue so that the calling code can
1009  // decide how to handle this situation.
1010  if (ec)
1011  {
1012  std::cerr << "Unable to create log file path " << log_dir
1013  << ": " << ec.message() << '\n';
1014  }
1015  }
1016  }
1017 
1018  return log_file;
1019 }
1020 
1021 int
1023 {
1024  auto const index = static_cast<std::underlying_type_t<SizedItem>>(item);
1025  assert(index < sizedItems.size());
1026  assert(!node || *node <= 4);
1027  return sizedItems.at(index).second.at(node.value_or(NODE_SIZE));
1028 }
1029 
1030 FeeSetup
1032 {
1033  FeeSetup setup;
1034  {
1035  std::uint64_t temp;
1036  if (set(temp, "reference_fee", section) &&
1038  setup.reference_fee = temp;
1039  }
1040  {
1041  std::uint32_t temp;
1042  if (set(temp, "account_reserve", section))
1043  setup.account_reserve = temp;
1044  if (set(temp, "owner_reserve", section))
1045  setup.owner_reserve = temp;
1046  }
1047  return setup;
1048 }
1049 
1050 } // 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:248
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:201
ripple::Config::LEDGER_REPLAY
bool LEDGER_REPLAY
Definition: Config.h:228
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:222
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:218
iterator
ripple::Config::PEER_PRIVATE
bool PEER_PRIVATE
Definition: Config.h:178
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:233
iostream
ripple::SizedItem::ledgerFetch
@ ledgerFetch
ripple::Config::MAX_TRANSACTIONS
int MAX_TRANSACTIONS
Definition: Config.h:231
ripple::Config::FETCH_DEPTH
std::uint32_t FETCH_DEPTH
Definition: Config.h:213
algorithm
ripple::Config::PATH_SEARCH_MAX
int PATH_SEARCH_MAX
Definition: Config.h:203
ripple::Config::VP_REDUCE_RELAY_SQUELCH
bool VP_REDUCE_RELAY_SQUELCH
Definition: Config.h:262
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:240
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:175
ripple::Config::SSL_VERIFY_FILE
std::string SSL_VERIFY_FILE
Definition: Config.h:221
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:1022
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:296
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:220
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:293
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:1031
ripple::Config::PEERS_OUT_MAX
std::size_t PEERS_OUT_MAX
Definition: Config.h:185
ripple::Config::AMENDMENT_MAJORITY_TIME
std::chrono::seconds AMENDMENT_MAJORITY_TIME
Definition: Config.h:236
ripple::SizedItem::lgrDBCache
@ lgrDBCache
ripple::Config::MAX_JOB_QUEUE_TX
static constexpr int MAX_JOB_QUEUE_TX
Definition: Config.h:232
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:239
ripple::Config::PEERS_IN_MAX
std::size_t PEERS_IN_MAX
Definition: Config.h:186
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:241
ripple::Config::PATH_SEARCH_OLD
int PATH_SEARCH_OLD
Definition: Config.h:200
ripple::Config::LEDGER_HISTORY
std::uint32_t LEDGER_HISTORY
Definition: Config.h:212
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:169
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:253
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:184
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:282
ripple::Config::PATH_SEARCH_FAST
int PATH_SEARCH_FAST
Definition: Config.h:202
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)
ripple::Config::NETWORK_ID
uint32_t NETWORK_ID
Definition: Config.h:161
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:274
ripple::Config::SERVER_DOMAIN
std::string SERVER_DOMAIN
Definition: Config.h:284
ripple::Config::TX_REDUCE_RELAY_METRICS
bool TX_REDUCE_RELAY_METRICS
Definition: Config.h:271
ripple::Config::RELAY_UNTRUSTED_VALIDATIONS
int RELAY_UNTRUSTED_VALIDATIONS
Definition: Config.h:174
ripple::SizedItem::sweepInterval
@ sweepInterval
ripple::Config::COMPRESSION
bool COMPRESSION
Definition: Config.h:225
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:277
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:264
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:988
ripple::Config::FEES
FeeSetup FEES
Definition: Config.h:209
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:287
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:290
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