20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/main/DBInit.h>
22 #include <ripple/app/rdb/Vacuum.h>
23 #include <ripple/basics/Log.h>
24 #include <ripple/basics/StringUtilities.h>
25 #include <ripple/basics/ThreadUtilities.h>
26 #include <ripple/basics/contract.h>
27 #include <ripple/beast/clock/basic_seconds_clock.h>
28 #include <ripple/core/Config.h>
29 #include <ripple/core/ConfigSections.h>
30 #include <ripple/core/TimeKeeper.h>
31 #include <ripple/json/to_string.h>
32 #include <ripple/net/RPCCall.h>
33 #include <ripple/protocol/BuildInfo.h>
34 #include <ripple/resource/Fees.h>
35 #include <ripple/rpc/RPCHandler.h>
38 #include <ripple/beast/unit_test/match.hpp>
39 #include <test/unit_test/multi_runner.h>
40 #endif // ENABLE_TESTS
42 #include <google/protobuf/stubs/common.h>
44 #include <boost/filesystem.hpp>
45 #include <boost/predef.h>
46 #include <boost/process.hpp>
47 #include <boost/program_options.hpp>
55 #include <sys/timeb.h>
56 #include <sys/types.h>
61 #if !BOOST_OS_LINUX && !BOOST_OS_WINDOWS && !BOOST_OS_MACOS
62 #error Supported platforms are: Linux, Windows and MacOS
66 #if (BOOST_OS_LINUX && (BOOST_OS_WINDOWS || BOOST_OS_MACOS)) || \
67 (BOOST_OS_MACOS && (BOOST_OS_WINDOWS || BOOST_OS_LINUX)) || \
68 (BOOST_OS_WINDOWS && (BOOST_OS_LINUX || BOOST_OS_MACOS))
69 #error Multiple supported platforms appear active at once
72 namespace po = boost::program_options;
85 if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
88 if (rl.rlim_cur == RLIM_INFINITY)
100 if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
107 j.
fatal() <<
"Insufficient number of file descriptors: " << needed
108 <<
" are needed, but only " <<
available <<
" are available.";
110 std::cerr <<
"Insufficient number of file descriptors: " << needed
112 <<
" are available.\n";
125 <<
systemName() <<
"d [options] <command> <params>\n"
128 " account_currencies <account> [<ledger>]\n"
129 " account_info <account>|<key> [<ledger>]\n"
130 " account_lines <account> <account>|\"\" [<ledger>]\n"
131 " account_channels <account> <account>|\"\" [<ledger>]\n"
132 " account_objects <account> [<ledger>]\n"
133 " account_offers <account>|<account_public_key> [<ledger>]\n"
134 " account_tx accountID [ledger_index_min [ledger_index_max "
137 " book_changes [<ledger hash|id>]\n"
138 " book_offers <taker_pays> <taker_gets> [<taker [<ledger> "
139 "[<limit> [<proof> [<marker>]]]]]\n"
140 " can_delete [<ledgerid>|<ledgerhash>|now|always|never]\n"
141 " channel_authorize <private_key> <channel_id> <drops>\n"
142 " channel_verify <public_key> <channel_id> <drops> <signature>\n"
143 " connect <ip> [<port>]\n"
145 " deposit_authorized <source_account> <destination_account> "
147 " download_shard [[<index> <url>]]\n"
148 " feature [<feature> [accept|reject]]\n"
149 " fetch_info [clear]\n"
150 " gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ "
153 " json <method> <json>\n"
154 " ledger [<id>|current|closed|validated] [full]\n"
159 " ledger_request <ledger>\n"
160 " log_level [[<partition>] <severity>]\n"
162 " manifest <public_key>\n"
163 " node_to_shard [status|start|stop]\n"
167 " peer_reservations_add <public_key> [<description>]\n"
168 " peer_reservations_del <public_key>\n"
169 " peer_reservations_list\n"
171 " ripple_path_find <json> [<ledger>]\n"
172 " server_info [counters]\n"
173 " server_state [counters]\n"
174 " sign <private_key> <tx_json> [offline]\n"
175 " sign_for <signer_address> <signer_private_key> <tx_json> "
178 " submit <tx_blob>|[<private_key> <tx_json>]\n"
179 " submit_multisigned <tx_json>\n"
181 " validation_create [<seed>|<pass_phrase>|<key>]\n"
184 " validator_list_sites\n"
186 " wallet_propose [<passphrase>]\n";
201 explicit multi_selector(
std::string const& patterns =
"")
204 boost::split(v, patterns, boost::algorithm::is_any_of(
","));
208 if (selectors_.empty() || !s.empty())
209 selectors_.emplace_back(
210 beast::unit_test::selector::automatch, s);
215 operator()(beast::unit_test::suite_info
const& s)
217 for (
auto& sel : selectors_)
226 return selectors_.size();
234 template <
class Runner>
236 anyMissing(Runner& runner, multi_selector
const& pred)
238 if (runner.tests() == 0)
240 runner.add_failures(1);
244 if (runner.suites() < pred.size())
246 auto const missing = pred.size() - runner.suites();
247 runner.add_failures(missing);
249 <<
" filters did not match any existing test suites"
273 if (!child && num_jobs == 1)
278 child_runner.arg(argument);
279 multi_selector pred(pattern);
280 auto const any_failed =
281 child_runner.run_multi(pred) || anyMissing(child_runner, pred);
296 for (
int i = 1; i < argc; ++i)
303 boost::process::exe = exe_name, boost::process::args = args);
305 int bad_child_exits = 0;
306 int terminated_child_exits = 0;
307 for (
auto& c : children)
319 ++terminated_child_exits;
324 anyMissing(parent_runner, multi_selector(pattern));
326 if (parent_runner.
any_failed() || bad_child_exits)
334 runner.arg(argument);
335 auto const anyFailed = runner.run_multi(multi_selector(pattern));
343 #endif // ENABLE_TESTS
347 run(
int argc,
char** argv)
353 po::variables_map vm;
357 importText +=
"Import an existing node database (specified in the [";
359 importText +=
"] configuration file section) into the current ";
360 importText +=
"node database (specified in the [";
362 importText +=
"] configuration file section).";
367 po::options_description gen(
"General Options");
369 "conf", po::value<std::string>(),
"Specify the configuration file.")(
370 "debug",
"Enable normally suppressed debug logging")(
371 "help,h",
"Display this message.")(
372 "newnodeid",
"Generate a new node identity for this server.")(
374 po::value<std::string>(),
375 "Specify the node identity for this server.")(
377 po::value<std::size_t>(),
378 "Override the minimum validation quorum.")(
379 "reportingReadOnly",
"Run in read-only reporting mode")(
380 "silent",
"No output to the console after startup.")(
381 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")
383 (
"force_ledger_present_range",
384 po::value<std::string>(),
385 "Specify the range of present ledgers for testing purposes. Min and "
386 "max values are comma separated.")(
387 "version",
"Display the build version.");
389 po::options_description
data(
"Ledger/Data Options");
390 data.add_options()(
"import", importText.
c_str())(
392 po::value<std::string>(),
393 "Load the specified ledger and start from the value given.")(
395 po::value<std::string>(),
396 "Load the specified ledger file.")(
397 "load",
"Load the current ledger from the local DB.")(
398 "net",
"Get the initial ledger from the network.")(
399 "nodetoshard",
"Import node store into shards")(
400 "replay",
"Replay a ledger close.")(
401 "start",
"Start from a fresh Ledger.")(
403 po::value<std::string>(),
404 "Start reporting from a fresh Ledger.")(
405 "vacuum",
"VACUUM the transaction db.")(
406 "valid",
"Consider the initial ledger a valid network ledger.");
408 po::options_description rpc(
"RPC Client Options");
411 "Perform rpc command - see below for available commands. "
412 "This is assumed if any positional parameters are provided.")(
414 po::value<std::string>(),
415 "Specify the IP address for RPC command. "
416 "Format: <ip-address>[':'<port-number>]")(
418 po::value<std::uint16_t>(),
419 "DEPRECATED: include with rpc_ip instead. "
420 "Specify the port number for RPC command.");
423 po::options_description test(
"Unit Test Options");
426 "Suppress test suite messages, "
427 "including suite/case name (at start) and test log messages.")(
429 po::value<std::string>()->implicit_value(
""),
430 "Perform unit tests. The optional argument specifies one or "
431 "more comma-separated selectors. Each selector specifies a suite name, "
432 "full-name (lib.module.suite), module, or library "
436 po::value<std::string>()->implicit_value(
""),
437 "Supplies an argument string to unit tests. If provided, this argument "
438 "is made available to each suite that runs. Interpretation of the "
439 "argument is handled individually by any suite that accesses it -- "
440 "as such, it typically only make sense to provide this when running "
443 "Use IPv6 localhost when running unittests (default is IPv4).")(
445 "Force unit test log message output. Only useful in combination with "
446 "--quiet, in which case log messages will print but suite/case names "
449 po::value<std::size_t>(),
450 "Number of unittest jobs to run in parallel (child processes).");
451 #endif // ENABLE_TESTS
455 po::options_description hidden(
"Hidden Options");
456 hidden.add_options()(
458 po::value<vector<string>>(),
459 "Specify rpc command and parameters. This option must be repeated "
460 "for each command/param. Positional parameters also serve this "
462 "so this option is not needed for users")
465 "For internal use only when spawning child unit test processes.")
467 (
"unittest",
"Disabled in this build.")(
468 "unittest-child",
"Disabled in this build.")
470 (
"fg",
"Deprecated: server always in foreground mode.");
473 po::positional_options_description p;
474 p.add(
"parameters", -1);
476 po::options_description
all;
482 #endif // ENABLE_TESTS
485 po::options_description desc;
491 #endif // ENABLE_TESTS
498 po::command_line_parser(argc, argv)
512 if (vm.count(
"help"))
518 if (vm.count(
"version"))
526 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
536 if (vm.count(
"unittest"))
540 if (vm.count(
"unittest-arg"))
544 bool unittestChild =
false;
545 if (vm.count(
"unittest-jobs"))
546 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
547 unittestChild = bool(vm.count(
"unittest-child"));
550 vm[
"unittest"].as<std::string>(),
552 bool(vm.count(
"quiet")),
553 bool(vm.count(
"unittest-log")),
555 bool(vm.count(
"unittest-ipv6")),
562 if (vm.count(
"unittest-jobs"))
565 std::cerr <<
"rippled: '--unittest-jobs' specified without "
567 std::cerr <<
"To run the unit tests the '--unittest' option must "
572 #endif // ENABLE_TESTS
574 auto config = std::make_unique<Config>();
582 bool(vm.count(
"quiet")),
583 bool(vm.count(
"silent")),
584 bool(vm.count(
"standalone")));
586 if (vm.count(
"vacuum"))
588 if (config->standalone())
590 std::cerr <<
"vacuum not applicable in standalone mode.\n";
602 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
610 if (vm.contains(
"force_ledger_present_range"))
618 vm[
"force_ledger_present_range"].as<std::string>(),
619 boost::algorithm::is_any_of(
","));
621 for (
auto& s : strVec)
635 "Invalid force_ledger_present_range parameter");
637 config->FORCED_LEDGER_RANGE_PRESENT.emplace(r[0], r[1]);
642 "Invalid force_ledger_present_range parameter");
647 std::cerr <<
"invalid 'force_ledger_present_range' parameter. The "
648 "parameter must be two numbers separated by a comma. "
649 "The first number must be <= the second."
655 if (vm.count(
"start"))
660 if (vm.count(
"startReporting"))
663 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
666 if (vm.count(
"reportingReadOnly"))
668 config->setReportingReadOnly(
true);
671 if (vm.count(
"import"))
672 config->doImport =
true;
674 if (vm.count(
"nodetoshard"))
675 config->nodeToShard =
true;
677 if (vm.count(
"ledger"))
679 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
680 if (vm.count(
"replay"))
685 else if (vm.count(
"ledgerfile"))
687 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
690 else if (vm.count(
"load") || config->FAST_LOAD)
695 if (vm.count(
"net") && !config->FAST_LOAD)
700 std::cerr <<
"Net and load/replay options are incompatible"
708 if (vm.count(
"valid"))
710 config->START_VALID =
true;
715 if (vm.count(
"rpc_ip"))
718 vm[
"rpc_ip"].as<std::string>());
726 if (endpoint->port() == 0)
728 std::cerr <<
"No port specified in rpc_ip.\n";
729 if (vm.count(
"rpc_port"))
731 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
735 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
736 if (endpoint->port() == 0)
749 config->rpc_ip = std::move(*endpoint);
752 if (vm.count(
"quorum"))
756 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
764 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
774 if (vm.count(
"quiet"))
776 else if (vm.count(
"verbose"))
779 auto logs = std::make_unique<Logs>(thresh);
782 if (!vm.count(
"parameters"))
786 if (config->had_trailing_comments())
788 JLOG(logs->journal(
"Application").warn())
789 <<
"Trailing comments were seen in your config file. "
790 <<
"The treatment of inline/trailing comments has changed "
792 <<
"Any `#` characters NOT intended to delimit comments should "
794 <<
"preceded by a \\";
802 if (vm.count(
"debug"))
808 std::move(config), std::move(logs), std::move(timeKeeper));
816 app->fdRequired(), app->logs().journal(
"Application")))
837 main(
int argc,
char** argv)
857 atexit(&google::protobuf::ShutdownProtobufLibrary);
859 return ripple::run(argc, argv);