rippled
Config_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2015 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/contract.h>
21 #include <ripple/core/Config.h>
22 #include <ripple/core/ConfigSections.h>
23 #include <ripple/server/Port.h>
24 #include <boost/filesystem.hpp>
25 #include <boost/format.hpp>
26 #include <fstream>
27 #include <iostream>
28 #include <test/jtx/TestSuite.h>
29 #include <test/unit_test/FileDirGuard.h>
30 
31 namespace ripple {
32 namespace detail {
34 configContents(std::string const& dbPath, std::string const& validatorsFile)
35 {
36  static boost::format configContentsTemplate(R"rippleConfig(
37 [server]
38 port_rpc
39 port_peer
40 port_wss_admin
41 
42 [port_rpc]
43 port = 5005
44 ip = 127.0.0.1
45 admin = 127.0.0.1, ::1
46 protocol = https
47 
48 [port_peer]
49 port = 51235
50 ip = 0.0.0.0
51 protocol = peer
52 
53 [port_wss_admin]
54 port = 6006
55 ip = 127.0.0.1
56 admin = 127.0.0.1
57 protocol = wss
58 
59 #[port_ws_public]
60 #port = 5005
61 #ip = 127.0.0.1
62 #protocol = wss
63 
64 #-------------------------------------------------------------------------------
65 
66 [node_size]
67 medium
68 
69 # This is primary persistent datastore for rippled. This includes transaction
70 # metadata, account states, and ledger headers. Helpful information can be
71 # found on https://xrpl.org/capacity-planning.html#node-db-type
72 # delete old ledgers while maintaining at least 2000. Do not require an
73 # external administrative command to initiate deletion.
74 [node_db]
75 type=memory
76 path=/Users/dummy/ripple/config/db/rocksdb
77 open_files=2000
78 filter_bits=12
79 cache_mb=256
80 file_size_mb=8
81 file_size_mult=2
82 
83 %1%
84 
85 %2%
86 
87 # This needs to be an absolute directory reference, not a relative one.
88 # Modify this value as required.
89 [debug_logfile]
90 /Users/dummy/ripple/config/log/debug.log
91 
92 [sntp_servers]
93 time.windows.com
94 time.apple.com
95 time.nist.gov
96 pool.ntp.org
97 
98 # Where to find some other servers speaking the Ripple protocol.
99 #
100 [ips]
101 r.ripple.com 51235
102 
103 # Turn down default logging to save disk space in the long run.
104 # Valid values here are trace, debug, info, warning, error, and fatal
105 [rpc_startup]
106 { "command": "log_level", "severity": "warning" }
107 
108 # Defaults to 1 ("yes") so that certificates will be validated. To allow the use
109 # of self-signed certificates for development or internal use, set to 0 ("no").
110 [ssl_verify]
111 0
112 
113 [sqdb]
114 backend=sqlite
115 )rippleConfig");
116 
117  std::string dbPathSection =
118  dbPath.empty() ? "" : "[database_path]\n" + dbPath;
119  std::string valFileSection =
120  validatorsFile.empty() ? "" : "[validators_file]\n" + validatorsFile;
121  return boost::str(configContentsTemplate % dbPathSection % valFileSection);
122 }
123 
128 {
129 private:
131 
132  bool rmDataDir_{false};
133 
135 
136 public:
138  beast::unit_test::suite& test,
139  path subDir,
140  path const& dbPath,
141  path const& validatorsFile,
142  bool useCounter = true)
143  : FileDirGuard(
144  test,
145  std::move(subDir),
146  path(Config::configFileName),
147  configContents(dbPath.string(), validatorsFile.string()),
148  useCounter)
149  , dataDir_(dbPath)
150  {
151  if (dbPath.empty())
153 
154  rmDataDir_ = !exists(dataDir_);
155  config_.setup(
156  file_.string(),
157  /* bQuiet */ true,
158  /* bSilent */ false,
159  /* bStandalone */ false);
160  }
161 
162  Config const&
163  config() const
164  {
165  return config_;
166  }
167 
169  configFile() const
170  {
171  return file().string();
172  }
173 
174  bool
176  {
177  return boost::filesystem::is_directory(dataDir_);
178  }
179 
180  bool
182  {
183  return fileExists();
184  }
185 
187  {
188  try
189  {
190  using namespace boost::filesystem;
191  if (rmDataDir_)
192  rmDir(dataDir_);
193  }
194  catch (std::exception& e)
195  {
196  // if we throw here, just let it die.
197  test_.log << "Error in ~RippledCfgGuard: " << e.what() << std::endl;
198  };
199  }
200 };
201 
204 {
205  std::string configContents(R"rippleConfig(
206 [validators]
207 n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
208 n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
209 n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
210 n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
211 n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
212 
213 [validator_keys]
214 nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
215 nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
216 nHUPDdcdb2Y5DZAJne4c2iabFuAP3F34xZUgYQT2NH7qfkdapgnz
217 
218 [validator_list_sites]
219 recommendedripplevalidators.com
220 moreripplevalidators.net
221 
222 [validator_list_keys]
223 03E74EE14CB525AFBB9F1B7D86CD58ECC4B91452294B42AB4E78F260BD905C091D
224 030775A669685BD6ABCEBD80385921C7851783D991A8055FD21D2F3966C96F1B56
225 )rippleConfig");
226  return configContents;
227 }
228 
233 {
234 public:
236  beast::unit_test::suite& test,
237  path subDir,
238  path const& validatorsFileName,
239  bool useCounter = true)
240  : FileDirGuard(
241  test,
242  std::move(subDir),
243  path(
244  validatorsFileName.empty() ? Config::validatorsFileName
245  : validatorsFileName),
246  valFileContents(),
247  useCounter)
248  {
249  }
250 
251  bool
253  {
254  return fileExists();
255  }
256 
259  {
260  return absolute(file()).string();
261  }
262 
264  {
265  }
266 };
267 } // namespace detail
268 
269 class Config_test final : public TestSuite
270 {
271 private:
272  using path = boost::filesystem::path;
273 
274 public:
275  void
277  {
278  testcase("legacy");
279 
280  Config c;
281 
282  std::string toLoad(R"rippleConfig(
283 [server]
284 port_rpc
285 port_peer
286 port_wss_admin
287 
288 [ssl_verify]
289 0
290 )rippleConfig");
291 
292  c.loadFromString(toLoad);
293 
294  BEAST_EXPECT(c.legacy("ssl_verify") == "0");
295  expectException([&c] { c.legacy("server"); }); // not a single line
296 
297  // set a legacy value
298  BEAST_EXPECT(c.legacy("not_in_file") == "");
299  c.legacy("not_in_file", "new_value");
300  BEAST_EXPECT(c.legacy("not_in_file") == "new_value");
301  }
302  void
304  {
305  testcase("database_path");
306 
307  using namespace boost::filesystem;
308  {
309  boost::format cc("[database_path]\n%1%\n");
310 
311  auto const cwd = current_path();
312  path const dataDirRel("test_data_dir");
313  path const dataDirAbs(cwd / dataDirRel);
314  {
315  // Dummy test - do we get back what we put in
316  Config c;
317  c.loadFromString(boost::str(cc % dataDirAbs.string()));
318  BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
319  }
320  {
321  // Rel paths should convert to abs paths
322  Config c;
323  c.loadFromString(boost::str(cc % dataDirRel.string()));
324  BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
325  }
326  {
327  // No db section.
328  // N.B. Config::setup will give database_path a default,
329  // load will not.
330  Config c;
331  c.loadFromString("");
332  BEAST_EXPECT(c.legacy("database_path") == "");
333  }
334  }
335  {
336  // read from file absolute path
337  auto const cwd = current_path();
338  ripple::test::detail::DirGuard const g0(*this, "test_db");
339  path const dataDirRel("test_data_dir");
340  path const dataDirAbs(cwd / g0.subdir() / dataDirRel);
341  detail::RippledCfgGuard const g(
342  *this, g0.subdir(), dataDirAbs, "", false);
343  auto const& c(g.config());
344  BEAST_EXPECT(g.dataDirExists());
345  BEAST_EXPECT(g.configFileExists());
346  BEAST_EXPECT(c.legacy("database_path") == dataDirAbs.string());
347  }
348  {
349  // read from file relative path
350  std::string const dbPath("my_db");
351  detail::RippledCfgGuard const g(*this, "test_db", dbPath, "");
352  auto const& c(g.config());
353  std::string const nativeDbPath = absolute(path(dbPath)).string();
354  BEAST_EXPECT(g.dataDirExists());
355  BEAST_EXPECT(g.configFileExists());
356  BEAST_EXPECT(c.legacy("database_path") == nativeDbPath);
357  }
358  {
359  // read from file no path
360  detail::RippledCfgGuard const g(*this, "test_db", "", "");
361  auto const& c(g.config());
362  std::string const nativeDbPath =
363  absolute(g.subdir() / path(Config::databaseDirName)).string();
364  BEAST_EXPECT(g.dataDirExists());
365  BEAST_EXPECT(g.configFileExists());
366  BEAST_EXPECT(c.legacy("database_path") == nativeDbPath);
367  }
368  }
369 
370  void
372  {
373  testcase("validator keys");
374 
375  std::string const validationSeed = "spA4sh1qTvwq92X715tYyGQKmAKfa";
376 
377  auto const token =
378  "eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiOWVkNDVmODY2MjQxY2MxOGEyNzQ3Yj"
379  "U0Mzg3YzA2MjU5MDc5NzJmNGU3MTkwMjMxZmFhOTM3NDU3ZmE5ZGFmNiIsIm1hbmlm"
380  "ZXN0IjoiSkFBQUFBRnhJZTFGdHdtaW12R3RIMmlDY01KcUM5Z1ZGS2lsR2Z3MS92Q3"
381  "hIWFhMcGxjMkduTWhBa0UxYWdxWHhCd0R3RGJJRDZPTVNZdU0wRkRBbHBBZ05rOFNL"
382  "Rm43TU8yZmRrY3dSUUloQU9uZ3U5c0FLcVhZb3VKK2wyVjBXK3NBT2tWQitaUlM2UF"
383  "NobEpBZlVzWGZBaUJzVkpHZXNhYWRPSmMvYUFab2tTMXZ5bUdtVnJsSFBLV1gzWXl3"
384  "dTZpbjhIQVNRS1B1Z0JENjdrTWFSRkd2bXBBVEhsR0tKZHZERmxXUFl5NUFxRGVkRn"
385  "Y1VEphMncwaTIxZXEzTVl5d0xWSlpuRk9yN0Mwa3cyQWlUelNDakl6ZGl0UTg9In0"
386  "=";
387 
388  {
389  Config c;
390  static boost::format configTemplate(R"rippleConfig(
391 [validation_seed]
392 %1%
393 
394 [validator_token]
395 %2%
396 )rippleConfig");
397  std::string error;
398  auto const expectedError =
399  "Cannot have both [validation_seed] "
400  "and [validator_token] config sections";
401  try
402  {
403  c.loadFromString(
404  boost::str(configTemplate % validationSeed % token));
405  }
406  catch (std::runtime_error& e)
407  {
408  error = e.what();
409  }
410  BEAST_EXPECT(error == expectedError);
411  }
412  }
413 
414  void
416  {
417  testcase("validators_file");
418 
419  using namespace boost::filesystem;
420  {
421  // load should throw for missing specified validators file
422  boost::format cc("[validators_file]\n%1%\n");
423  std::string error;
424  std::string const missingPath = "/no/way/this/path/exists";
425  auto const expectedError =
426  "The file specified in [validators_file] does not exist: " +
427  missingPath;
428  try
429  {
430  Config c;
431  c.loadFromString(boost::str(cc % missingPath));
432  }
433  catch (std::runtime_error& e)
434  {
435  error = e.what();
436  }
437  BEAST_EXPECT(error == expectedError);
438  }
439  {
440  // load should throw for invalid [validators_file]
441  detail::ValidatorsTxtGuard const vtg(
442  *this, "test_cfg", "validators.cfg");
443  path const invalidFile = current_path() / vtg.subdir();
444  boost::format cc("[validators_file]\n%1%\n");
445  std::string error;
446  auto const expectedError =
447  "Invalid file specified in [validators_file]: " +
448  invalidFile.string();
449  try
450  {
451  Config c;
452  c.loadFromString(boost::str(cc % invalidFile.string()));
453  }
454  catch (std::runtime_error& e)
455  {
456  error = e.what();
457  }
458  BEAST_EXPECT(error == expectedError);
459  }
460  {
461  // load validators from config into single section
462  Config c;
463  std::string toLoad(R"rippleConfig(
464 [validators]
465 n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
466 n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
467 n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
468 
469 [validator_keys]
470 nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
471 nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
472 )rippleConfig");
473  c.loadFromString(toLoad);
474  BEAST_EXPECT(c.legacy("validators_file").empty());
475  BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 5);
476  }
477  {
478  // load validator list sites and keys from config
479  Config c;
480  std::string toLoad(R"rippleConfig(
481 [validator_list_sites]
482 ripplevalidators.com
483 trustthesevalidators.gov
484 
485 [validator_list_keys]
486 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
487 )rippleConfig");
488  c.loadFromString(toLoad);
489  BEAST_EXPECT(
490  c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
491  BEAST_EXPECT(
492  c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] ==
493  "ripplevalidators.com");
494  BEAST_EXPECT(
495  c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] ==
496  "trustthesevalidators.gov");
497  BEAST_EXPECT(
498  c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 1);
499  BEAST_EXPECT(
500  c.section(SECTION_VALIDATOR_LIST_KEYS).values()[0] ==
501  "021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801"
502  "E566");
503  }
504  {
505  // load should throw if [validator_list_sites] is configured but
506  // [validator_list_keys] is not
507  Config c;
508  std::string toLoad(R"rippleConfig(
509 [validator_list_sites]
510 ripplevalidators.com
511 trustthesevalidators.gov
512 )rippleConfig");
513  std::string error;
514  auto const expectedError =
515  "[validator_list_keys] config section is missing";
516  try
517  {
518  c.loadFromString(toLoad);
519  }
520  catch (std::runtime_error& e)
521  {
522  error = e.what();
523  }
524  BEAST_EXPECT(error == expectedError);
525  }
526  {
527  // load from specified [validators_file] absolute path
528  detail::ValidatorsTxtGuard const vtg(
529  *this, "test_cfg", "validators.cfg");
530  BEAST_EXPECT(vtg.validatorsFileExists());
531  Config c;
532  boost::format cc("[validators_file]\n%1%\n");
533  c.loadFromString(boost::str(cc % vtg.validatorsFile()));
534  BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
535  BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
536  BEAST_EXPECT(
537  c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
538  BEAST_EXPECT(
539  c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
540  }
541  {
542  // load from specified [validators_file] file name
543  // in config directory
544  std::string const valFileName = "validators.txt";
545  detail::ValidatorsTxtGuard const vtg(
546  *this, "test_cfg", valFileName);
547  detail::RippledCfgGuard const rcg(
548  *this, vtg.subdir(), "", valFileName, false);
549  BEAST_EXPECT(vtg.validatorsFileExists());
550  BEAST_EXPECT(rcg.configFileExists());
551  auto const& c(rcg.config());
552  BEAST_EXPECT(c.legacy("validators_file") == valFileName);
553  BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
554  BEAST_EXPECT(
555  c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
556  BEAST_EXPECT(
557  c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
558  }
559  {
560  // load from specified [validators_file] relative path
561  // to config directory
562  detail::ValidatorsTxtGuard const vtg(
563  *this, "test_cfg", "validators.txt");
564  auto const valFilePath = ".." / vtg.subdir() / "validators.txt";
565  detail::RippledCfgGuard const rcg(
566  *this, vtg.subdir(), "", valFilePath, false);
567  BEAST_EXPECT(vtg.validatorsFileExists());
568  BEAST_EXPECT(rcg.configFileExists());
569  auto const& c(rcg.config());
570  BEAST_EXPECT(c.legacy("validators_file") == valFilePath);
571  BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
572  BEAST_EXPECT(
573  c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
574  BEAST_EXPECT(
575  c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
576  }
577  {
578  // load from validators file in default location
579  detail::ValidatorsTxtGuard const vtg(
580  *this, "test_cfg", "validators.txt");
581  detail::RippledCfgGuard const rcg(
582  *this, vtg.subdir(), "", "", false);
583  BEAST_EXPECT(vtg.validatorsFileExists());
584  BEAST_EXPECT(rcg.configFileExists());
585  auto const& c(rcg.config());
586  BEAST_EXPECT(c.legacy("validators_file").empty());
587  BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
588  BEAST_EXPECT(
589  c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
590  BEAST_EXPECT(
591  c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
592  }
593  {
594  // load from specified [validators_file] instead
595  // of default location
596  detail::ValidatorsTxtGuard const vtg(
597  *this, "test_cfg", "validators.cfg");
598  BEAST_EXPECT(vtg.validatorsFileExists());
599  detail::ValidatorsTxtGuard const vtgDefault(
600  *this, vtg.subdir(), "validators.txt", false);
601  BEAST_EXPECT(vtgDefault.validatorsFileExists());
602  detail::RippledCfgGuard const rcg(
603  *this, vtg.subdir(), "", vtg.validatorsFile(), false);
604  BEAST_EXPECT(rcg.configFileExists());
605  auto const& c(rcg.config());
606  BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
607  BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 8);
608  BEAST_EXPECT(
609  c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
610  BEAST_EXPECT(
611  c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 2);
612  }
613 
614  {
615  // load validators from both config and validators file
616  boost::format cc(R"rippleConfig(
617 [validators_file]
618 %1%
619 
620 [validators]
621 n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
622 n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
623 n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
624 n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
625 n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
626 
627 [validator_keys]
628 nHB1X37qrniVugfQcuBTAjswphC1drx7QjFFojJPZwKHHnt8kU7v
629 nHUkAWDR4cB8AgPg7VXMX6et8xRTQb2KJfgv1aBEXozwrawRKgMB
630 
631 [validator_list_sites]
632 ripplevalidators.com
633 trustthesevalidators.gov
634 
635 [validator_list_keys]
636 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
637 )rippleConfig");
638  detail::ValidatorsTxtGuard const vtg(
639  *this, "test_cfg", "validators.cfg");
640  BEAST_EXPECT(vtg.validatorsFileExists());
641  Config c;
642  c.loadFromString(boost::str(cc % vtg.validatorsFile()));
643  BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
644  BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 15);
645  BEAST_EXPECT(
646  c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 4);
647  BEAST_EXPECT(
648  c.section(SECTION_VALIDATOR_LIST_KEYS).values().size() == 3);
649  }
650  {
651  // load should throw if [validators], [validator_keys] and
652  // [validator_list_keys] are missing from rippled cfg and
653  // validators file
654  Config c;
655  boost::format cc("[validators_file]\n%1%\n");
656  std::string error;
657  detail::ValidatorsTxtGuard const vtg(
658  *this, "test_cfg", "validators.cfg");
659  BEAST_EXPECT(vtg.validatorsFileExists());
660  auto const expectedError =
661  "The file specified in [validators_file] does not contain a "
662  "[validators], [validator_keys] or [validator_list_keys] "
663  "section: " +
664  vtg.validatorsFile();
665  std::ofstream o(vtg.validatorsFile());
666  try
667  {
668  Config c2;
669  c2.loadFromString(boost::str(cc % vtg.validatorsFile()));
670  }
671  catch (std::runtime_error& e)
672  {
673  error = e.what();
674  }
675  BEAST_EXPECT(error == expectedError);
676  }
677  }
678 
679  void
680  testSetup(bool explicitPath)
681  {
682  detail::RippledCfgGuard const cfg(
683  *this, "testSetup", explicitPath ? "test_db" : "", "");
684  /* RippledCfgGuard has a Config object that gets loaded on
685  construction, but Config::setup is not reentrant, so we
686  need a fresh config for every test case, so ignore it.
687  */
688  {
689  Config config;
690  config.setup(
691  cfg.configFile(),
692  /*bQuiet*/ false,
693  /* bSilent */ false,
694  /* bStandalone */ false);
695  BEAST_EXPECT(!config.quiet());
696  BEAST_EXPECT(!config.silent());
697  BEAST_EXPECT(!config.standalone());
698  BEAST_EXPECT(config.LEDGER_HISTORY == 256);
699  BEAST_EXPECT(!config.legacy("database_path").empty());
700  }
701  {
702  Config config;
703  config.setup(
704  cfg.configFile(),
705  /*bQuiet*/ true,
706  /* bSilent */ false,
707  /* bStandalone */ false);
708  BEAST_EXPECT(config.quiet());
709  BEAST_EXPECT(!config.silent());
710  BEAST_EXPECT(!config.standalone());
711  BEAST_EXPECT(config.LEDGER_HISTORY == 256);
712  BEAST_EXPECT(!config.legacy("database_path").empty());
713  }
714  {
715  Config config;
716  config.setup(
717  cfg.configFile(),
718  /*bQuiet*/ false,
719  /* bSilent */ true,
720  /* bStandalone */ false);
721  BEAST_EXPECT(config.quiet());
722  BEAST_EXPECT(config.silent());
723  BEAST_EXPECT(!config.standalone());
724  BEAST_EXPECT(config.LEDGER_HISTORY == 256);
725  BEAST_EXPECT(!config.legacy("database_path").empty());
726  }
727  {
728  Config config;
729  config.setup(
730  cfg.configFile(),
731  /*bQuiet*/ true,
732  /* bSilent */ true,
733  /* bStandalone */ false);
734  BEAST_EXPECT(config.quiet());
735  BEAST_EXPECT(config.silent());
736  BEAST_EXPECT(!config.standalone());
737  BEAST_EXPECT(config.LEDGER_HISTORY == 256);
738  BEAST_EXPECT(!config.legacy("database_path").empty());
739  }
740  {
741  Config config;
742  config.setup(
743  cfg.configFile(),
744  /*bQuiet*/ false,
745  /* bSilent */ false,
746  /* bStandalone */ true);
747  BEAST_EXPECT(!config.quiet());
748  BEAST_EXPECT(!config.silent());
749  BEAST_EXPECT(config.standalone());
750  BEAST_EXPECT(config.LEDGER_HISTORY == 0);
751  BEAST_EXPECT(
752  config.legacy("database_path").empty() == !explicitPath);
753  }
754  {
755  Config config;
756  config.setup(
757  cfg.configFile(),
758  /*bQuiet*/ true,
759  /* bSilent */ false,
760  /* bStandalone */ true);
761  BEAST_EXPECT(config.quiet());
762  BEAST_EXPECT(!config.silent());
763  BEAST_EXPECT(config.standalone());
764  BEAST_EXPECT(config.LEDGER_HISTORY == 0);
765  BEAST_EXPECT(
766  config.legacy("database_path").empty() == !explicitPath);
767  }
768  {
769  Config config;
770  config.setup(
771  cfg.configFile(),
772  /*bQuiet*/ false,
773  /* bSilent */ true,
774  /* bStandalone */ true);
775  BEAST_EXPECT(config.quiet());
776  BEAST_EXPECT(config.silent());
777  BEAST_EXPECT(config.standalone());
778  BEAST_EXPECT(config.LEDGER_HISTORY == 0);
779  BEAST_EXPECT(
780  config.legacy("database_path").empty() == !explicitPath);
781  }
782  {
783  Config config;
784  config.setup(
785  cfg.configFile(),
786  /*bQuiet*/ true,
787  /* bSilent */ true,
788  /* bStandalone */ true);
789  BEAST_EXPECT(config.quiet());
790  BEAST_EXPECT(config.silent());
791  BEAST_EXPECT(config.standalone());
792  BEAST_EXPECT(config.LEDGER_HISTORY == 0);
793  BEAST_EXPECT(
794  config.legacy("database_path").empty() == !explicitPath);
795  }
796  }
797 
798  void
800  {
801  detail::RippledCfgGuard const cfg(*this, "testPort", "", "");
802  auto const& conf = cfg.config();
803  if (!BEAST_EXPECT(conf.exists("port_rpc")))
804  return;
805  if (!BEAST_EXPECT(conf.exists("port_wss_admin")))
806  return;
807  ParsedPort rpc;
808  if (!unexcept([&]() { parse_Port(rpc, conf["port_rpc"], log); }))
809  return;
810  BEAST_EXPECT(rpc.admin_nets_v4.size() + rpc.admin_nets_v6.size() == 2);
811  ParsedPort wss;
812  if (!unexcept([&]() { parse_Port(wss, conf["port_wss_admin"], log); }))
813  return;
814  BEAST_EXPECT(wss.admin_nets_v4.size() + wss.admin_nets_v6.size() == 1);
815  }
816 
817  void
819  {
820  Config cfg;
821  /* NOTE: this string includes some explicit
822  * space chars in order to verify proper trimming */
823  std::string toLoad(R"(
824 [port_rpc])"
825  "\x20"
826  R"(
827 # comment
828  # indented comment
829 )"
830  "\x20\x20"
831  R"(
832 [ips])"
833  "\x20"
834  R"(
835 r.ripple.com 51235
836 
837  [ips_fixed])"
838  "\x20\x20"
839  R"(
840  # COMMENT
841  s1.ripple.com 51235
842  s2.ripple.com 51235
843 
844 )");
845  cfg.loadFromString(toLoad);
846  BEAST_EXPECT(
847  cfg.exists("port_rpc") && cfg.section("port_rpc").lines().empty() &&
848  cfg.section("port_rpc").values().empty());
849  BEAST_EXPECT(
850  cfg.exists(SECTION_IPS) &&
851  cfg.section(SECTION_IPS).lines().size() == 1 &&
852  cfg.section(SECTION_IPS).values().size() == 1);
853  BEAST_EXPECT(
854  cfg.exists(SECTION_IPS_FIXED) &&
855  cfg.section(SECTION_IPS_FIXED).lines().size() == 2 &&
856  cfg.section(SECTION_IPS_FIXED).values().size() == 2);
857  }
858 
859  void
860  testComments()
861  {
862  struct TestCommentData
863  {
864  std::string_view line;
865  std::string_view field;
866  std::string_view expect;
867  bool had_comment;
868  };
869 
871  {{"password = aaaa\\#bbbb", "password", "aaaa#bbbb", false},
872  {"password = aaaa#bbbb", "password", "aaaa", true},
873  {"password = aaaa #bbbb", "password", "aaaa", true},
874  // since the value is all comment, this doesn't parse as k=v :
875  {"password = #aaaa #bbbb", "", "password =", true},
876  {"password = aaaa\\# #bbbb", "password", "aaaa#", true},
877  {"password = aaaa\\##bbbb", "password", "aaaa#", true},
878  {"aaaa#bbbb", "", "aaaa", true},
879  {"aaaa\\#bbbb", "", "aaaa#bbbb", false},
880  {"aaaa\\##bbbb", "", "aaaa#", true},
881  {"aaaa #bbbb", "", "aaaa", true},
882  {"1 #comment", "", "1", true},
883  {"#whole thing is comment", "", "", false},
884  {" #whole comment with space", "", "", false}}};
885 
886  for (auto const& t : tests)
887  {
888  Section s;
889  s.append(t.line.data());
890  BEAST_EXPECT(s.had_trailing_comments() == t.had_comment);
891  if (t.field.empty())
892  {
893  BEAST_EXPECTS(s.legacy() == t.expect, s.legacy());
894  }
895  else
896  {
898  BEAST_EXPECTS(set(field, t.field.data(), s), t.line);
899  BEAST_EXPECTS(field == t.expect, t.line);
900  }
901  }
902 
903  {
904  Section s;
905  s.append("online_delete = 3000");
906  std::uint32_t od = 0;
907  BEAST_EXPECT(set(od, "online_delete", s));
908  BEAST_EXPECTS(od == 3000, *(s.get<std::string>("online_delete")));
909  }
910 
911  {
912  Section s;
913  s.append("online_delete = 2000 #my comment on this");
914  std::uint32_t od = 0;
915  BEAST_EXPECT(set(od, "online_delete", s));
916  BEAST_EXPECTS(od == 2000, *(s.get<std::string>("online_delete")));
917  }
918  }
919 
920  void
921  testGetters()
922  {
923  using namespace std::string_literals;
924  Section s{"MySection"};
925  s.append("a_string = mystring");
926  s.append("positive_int = 2");
927  s.append("negative_int = -3");
928  s.append("bool_ish = 1");
929 
930  {
931  auto val_1 = "value 1"s;
932  BEAST_EXPECT(set(val_1, "a_string", s));
933  BEAST_EXPECT(val_1 == "mystring");
934 
935  auto val_2 = "value 2"s;
936  BEAST_EXPECT(!set(val_2, "not_a_key", s));
937  BEAST_EXPECT(val_2 == "value 2");
938  BEAST_EXPECT(!set(val_2, "default"s, "not_a_key", s));
939  BEAST_EXPECT(val_2 == "default");
940 
941  auto val_3 = get<std::string>(s, "a_string");
942  BEAST_EXPECT(val_3 == "mystring");
943  auto val_4 = get<std::string>(s, "not_a_key");
944  BEAST_EXPECT(val_4 == "");
945  auto val_5 = get<std::string>(s, "not_a_key", "default");
946  BEAST_EXPECT(val_5 == "default");
947 
948  auto val_6 = "value 6"s;
949  BEAST_EXPECT(get_if_exists(s, "a_string", val_6));
950  BEAST_EXPECT(val_6 == "mystring");
951 
952  auto val_7 = "value 7"s;
953  BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_7));
954  BEAST_EXPECT(val_7 == "value 7");
955  }
956 
957  {
958  int val_1 = 1;
959  BEAST_EXPECT(set(val_1, "positive_int", s));
960  BEAST_EXPECT(val_1 == 2);
961 
962  int val_2 = 2;
963  BEAST_EXPECT(set(val_2, "negative_int", s));
964  BEAST_EXPECT(val_2 == -3);
965 
966  int val_3 = 3;
967  BEAST_EXPECT(!set(val_3, "a_string", s));
968  BEAST_EXPECT(val_3 == 3);
969 
970  auto val_4 = get<int>(s, "positive_int");
971  BEAST_EXPECT(val_4 == 2);
972  auto val_5 = get<int>(s, "not_a_key");
973  BEAST_EXPECT(val_5 == 0);
974  auto val_6 = get<int>(s, "not_a_key", 5);
975  BEAST_EXPECT(val_6 == 5);
976  auto val_7 = get<int>(s, "a_string", 6);
977  BEAST_EXPECT(val_7 == 6);
978 
979  int val_8 = 8;
980  BEAST_EXPECT(get_if_exists(s, "positive_int", val_8));
981  BEAST_EXPECT(val_8 == 2);
982 
983  auto val_9 = 9;
984  BEAST_EXPECT(!get_if_exists(s, "not_a_key", val_9));
985  BEAST_EXPECT(val_9 == 9);
986 
987  auto val_10 = 10;
988  BEAST_EXPECT(!get_if_exists(s, "a_string", val_10));
989  BEAST_EXPECT(val_10 == 10);
990 
991  BEAST_EXPECT(s.get<int>("not_a_key") == std::nullopt);
992  try
993  {
994  s.get<int>("a_string");
995  fail();
996  }
997  catch (boost::bad_lexical_cast&)
998  {
999  pass();
1000  }
1001  }
1002 
1003  {
1004  bool flag_1 = false;
1005  BEAST_EXPECT(get_if_exists(s, "bool_ish", flag_1));
1006  BEAST_EXPECT(flag_1 == true);
1007 
1008  bool flag_2 = false;
1009  BEAST_EXPECT(!get_if_exists(s, "not_a_key", flag_2));
1010  BEAST_EXPECT(flag_2 == false);
1011  }
1012  }
1013 
1014  void
1015  testAmendment()
1016  {
1017  testcase("amendment");
1018  struct ConfigUnit
1019  {
1020  std::string unit;
1021  std::uint32_t numSeconds;
1022  std::uint32_t configVal;
1023  bool shouldPass;
1024  };
1025 
1026  std::vector<ConfigUnit> units = {
1027  {"seconds", 1, 15 * 60, false},
1028  {"minutes", 60, 14, false},
1029  {"minutes", 60, 15, true},
1030  {"hours", 3600, 10, true},
1031  {"days", 86400, 10, true},
1032  {"weeks", 604800, 2, true},
1033  {"months", 2592000, 1, false},
1034  {"years", 31536000, 1, false}};
1035 
1036  std::string space = "";
1037  for (auto& [unit, sec, val, shouldPass] : units)
1038  {
1039  Config c;
1040  std::string toLoad(R"rippleConfig(
1041 [amendment_majority_time]
1042 )rippleConfig");
1043  toLoad += std::to_string(val) + space + unit;
1044  space = space == "" ? " " : "";
1045 
1046  try
1047  {
1048  c.loadFromString(toLoad);
1049  if (shouldPass)
1050  BEAST_EXPECT(
1051  c.AMENDMENT_MAJORITY_TIME.count() == val * sec);
1052  else
1053  fail();
1054  }
1055  catch (std::runtime_error&)
1056  {
1057  if (!shouldPass)
1058  pass();
1059  else
1060  fail();
1061  }
1062  }
1063  }
1064 
1065  void
1066  testOverlay()
1067  {
1068  testcase("overlay: unknown time");
1069 
1070  auto testUnknown =
1072  try
1073  {
1074  Config c;
1075  c.loadFromString("[overlay]\nmax_unknown_time=" + value);
1076  return c.MAX_UNKNOWN_TIME;
1077  }
1078  catch (std::runtime_error&)
1079  {
1080  return {};
1081  }
1082  };
1083 
1084  // Failures
1085  BEAST_EXPECT(!testUnknown("none"));
1086  BEAST_EXPECT(!testUnknown("0.5"));
1087  BEAST_EXPECT(!testUnknown("180 seconds"));
1088  BEAST_EXPECT(!testUnknown("9 minutes"));
1089 
1090  // Below lower bound
1091  BEAST_EXPECT(!testUnknown("299"));
1092 
1093  // In bounds
1094  BEAST_EXPECT(testUnknown("300") == std::chrono::seconds{300});
1095  BEAST_EXPECT(testUnknown("301") == std::chrono::seconds{301});
1096  BEAST_EXPECT(testUnknown("1799") == std::chrono::seconds{1799});
1097  BEAST_EXPECT(testUnknown("1800") == std::chrono::seconds{1800});
1098 
1099  // Above upper bound
1100  BEAST_EXPECT(!testUnknown("1801"));
1101 
1102  testcase("overlay: diverged time");
1103 
1104  // In bounds:
1105  auto testDiverged =
1107  try
1108  {
1109  Config c;
1110  c.loadFromString("[overlay]\nmax_diverged_time=" + value);
1111  return c.MAX_DIVERGED_TIME;
1112  }
1113  catch (std::runtime_error&)
1114  {
1115  return {};
1116  }
1117  };
1118 
1119  // Failures
1120  BEAST_EXPECT(!testDiverged("none"));
1121  BEAST_EXPECT(!testDiverged("0.5"));
1122  BEAST_EXPECT(!testDiverged("180 seconds"));
1123  BEAST_EXPECT(!testDiverged("9 minutes"));
1124 
1125  // Below lower bound
1126  BEAST_EXPECT(!testDiverged("0"));
1127  BEAST_EXPECT(!testDiverged("59"));
1129  // In bounds
1130  BEAST_EXPECT(testDiverged("60") == std::chrono::seconds{60});
1131  BEAST_EXPECT(testDiverged("61") == std::chrono::seconds{61});
1132  BEAST_EXPECT(testDiverged("899") == std::chrono::seconds{899});
1133  BEAST_EXPECT(testDiverged("900") == std::chrono::seconds{900});
1134 
1135  // Above upper bound
1136  BEAST_EXPECT(!testDiverged("901"));
1137  }
1138 
1139  void
1140  run() override
1141  {
1142  testLegacy();
1143  testDbPath();
1144  testValidatorKeys();
1145  testValidatorsFile();
1146  testSetup(false);
1147  testSetup(true);
1148  testPort();
1149  testWhitespace();
1150  testComments();
1151  testGetters();
1152  testAmendment();
1153  testOverlay();
1154  }
1155 };
1156 
1157 BEAST_DEFINE_TESTSUITE(Config, core, ripple);
1158 
1159 } // namespace ripple
ripple::Config_test::testWhitespace
void testWhitespace()
Definition: Config_test.cpp:818
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:42
ripple::Config_test
Definition: Config_test.cpp:269
ripple::detail::RippledCfgGuard::RippledCfgGuard
RippledCfgGuard(beast::unit_test::suite &test, path subDir, path const &dbPath, path const &validatorsFile, bool useCounter=true)
Definition: Config_test.cpp:137
fstream
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::detail::ValidatorsTxtGuard::ValidatorsTxtGuard
ValidatorsTxtGuard(beast::unit_test::suite &test, path subDir, path const &validatorsFileName, bool useCounter=true)
Definition: Config_test.cpp:235
std::exception
STL class.
std::string_view
STL class.
ripple::test::detail::DirGuard
Create a directory and remove it when it's done.
Definition: FileDirGuard.h:34
ripple::ParsedPort::admin_nets_v6
std::vector< boost::asio::ip::network_v6 > admin_nets_v6
Definition: Port.h:117
ripple::Config_test::testSetup
void testSetup(bool explicitPath)
Definition: Config_test.cpp:680
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::detail::RippledCfgGuard::config_
Config config_
Definition: Config_test.cpp:134
std::chrono::seconds
ripple::Config::silent
bool silent() const
Definition: Config.h:306
ripple::detail::ValidatorsTxtGuard::validatorsFile
std::string validatorsFile() const
Definition: Config_test.cpp:258
ripple::Config_test::testDbPath
void testDbPath()
Definition: Config_test.cpp:303
ripple::parse_Port
void parse_Port(ParsedPort &port, Section const &section, std::ostream &log)
Definition: Port.cpp:199
ripple::Config_test::path
boost::filesystem::path path
Definition: Config_test.cpp:272
ripple::ParsedPort
Definition: Port.h:96
iostream
ripple::Config::quiet
bool quiet() const
Definition: Config.h:301
ripple::test::detail::DirGuard::subdir
path const & subdir() const
Definition: FileDirGuard.h:98
ripple::Section::values
std::vector< std::string > const & values() const
Returns all the values in the section.
Definition: BasicConfig.h:77
ripple::detail::RippledCfgGuard::~RippledCfgGuard
~RippledCfgGuard()
Definition: Config_test.cpp:186
ripple::get_if_exists
bool get_if_exists(Section const &section, std::string const &name, T &v)
Definition: BasicConfig.h:384
ripple::Section::append
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
Definition: BasicConfig.cpp:38
ripple::Config_test::testLegacy
void testLegacy()
Definition: Config_test.cpp:276
ripple::test::detail::FileDirGuard::file
path const & file() const
Definition: FileDirGuard.h:164
ripple::detail::ValidatorsTxtGuard::validatorsFileExists
bool validatorsFileExists() const
Definition: Config_test.cpp:252
ripple::Config::loadFromString
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition: Config.cpp:457
ripple::detail::RippledCfgGuard::configFile
std::string configFile() const
Definition: Config_test.cpp:169
ripple::Config
Definition: Config.h:68
std::ofstream
STL class.
ripple::Config_test::testPort
void testPort()
Definition: Config_test.cpp:799
ripple::Config::standalone
bool standalone() const
Definition: Config.h:311
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::validationSeed
static std::optional< Seed > validationSeed(Json::Value const &params)
Definition: ValidationCreate.cpp:30
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::Section::lines
std::vector< std::string > const & lines() const
Returns all the lines in the section.
Definition: BasicConfig.h:68
ripple::detail::valFileContents
std::string valFileContents()
Definition: Config_test.cpp:203
std::runtime_error
STL class.
ripple::test::detail::DirGuard::test_
beast::unit_test::suite & test_
Definition: FileDirGuard.h:44
std::uint32_t
ripple::Config::databaseDirName
static char const *const databaseDirName
Definition: Config.h:73
ripple::detail::RippledCfgGuard::configFileExists
bool configFileExists() const
Definition: Config_test.cpp:181
ripple::detail::RippledCfgGuard
Write a rippled config file and remove when done.
Definition: Config_test.cpp:127
ripple::Config::LEDGER_HISTORY
std::uint32_t LEDGER_HISTORY
Definition: Config.h:191
ripple::TestSuite
Definition: TestSuite.h:28
std::experimental::filesystem::space
T space(T... args)
beast::field
field_t< CharT, Traits, Allocator > field(std::basic_string< CharT, Traits, Allocator > const &text, int width=8, int pad=0, bool right=false)
Definition: iosformat.h:162
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::detail::FileDirGuard::FileDirGuard
FileDirGuard(beast::unit_test::suite &test, path subDir, path file, std::string const &contents, bool useCounter=true, bool create=true)
Definition: FileDirGuard.h:114
ripple::detail::RippledCfgGuard::rmDataDir_
bool rmDataDir_
Definition: Config_test.cpp:132
ripple::Config::setup
void setup(std::string const &strConf, bool bQuiet, bool bSilent, bool bStandalone)
Definition: Config.cpp:315
std::endl
T endl(T... args)
ripple::Config_test::testValidatorsFile
void testValidatorsFile()
Definition: Config_test.cpp:415
std
STL namespace.
ripple::Section::get
std::optional< T > get(std::string const &name) const
Definition: BasicConfig.h:138
std::string::empty
T empty(T... args)
std::optional
ripple::test::detail::FileDirGuard::fileExists
bool fileExists() const
Definition: FileDirGuard.h:170
ripple::test::detail::FileDirGuard
Write a file in a directory and remove when done.
Definition: FileDirGuard.h:107
ripple::test::detail::DirGuard::rmDir
auto rmDir(path const &toRm)
Definition: FileDirGuard.h:47
ripple::Config_test::testValidatorKeys
void testValidatorKeys()
Definition: Config_test.cpp:371
ripple::test::detail::FileDirGuard::file_
const path file_
Definition: FileDirGuard.h:110
ripple::detail::RippledCfgGuard::dataDirExists
bool dataDirExists() const
Definition: Config_test.cpp:175
ripple::detail::ValidatorsTxtGuard
Write a validators.txt file and remove when done.
Definition: Config_test.cpp:232
ripple::detail::configContents
std::string configContents(std::string const &dbPath, std::string const &validatorsFile)
Definition: Config_test.cpp:34
ripple::detail::RippledCfgGuard::dataDir_
path dataDir_
Definition: Config_test.cpp:130
ripple::test::detail::DirGuard::path
boost::filesystem::path path
Definition: FileDirGuard.h:37
ripple::detail::ValidatorsTxtGuard::~ValidatorsTxtGuard
~ValidatorsTxtGuard()
Definition: Config_test.cpp:263
std::exception::what
T what(T... args)
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::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:127
ripple::detail::RippledCfgGuard::config
Config const & config() const
Definition: Config_test.cpp:163
ripple::ParsedPort::admin_nets_v4
std::vector< boost::asio::ip::network_v4 > admin_nets_v4
Definition: Port.h:116