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.")(
382 "version",
"Display the build version.");
384 po::options_description
data(
"Ledger/Data Options");
385 data.add_options()(
"import", importText.
c_str())(
387 po::value<std::string>(),
388 "Load the specified ledger and start from the value given.")(
390 po::value<std::string>(),
391 "Load the specified ledger file.")(
392 "load",
"Load the current ledger from the local DB.")(
393 "net",
"Get the initial ledger from the network.")(
394 "nodetoshard",
"Import node store into shards")(
395 "replay",
"Replay a ledger close.")(
396 "start",
"Start from a fresh Ledger.")(
398 po::value<std::string>(),
399 "Start reporting from a fresh Ledger.")(
400 "vacuum",
"VACUUM the transaction db.")(
401 "valid",
"Consider the initial ledger a valid network ledger.");
403 po::options_description rpc(
"RPC Client Options");
406 "Perform rpc command - see below for available commands. "
407 "This is assumed if any positional parameters are provided.")(
409 po::value<std::string>(),
410 "Specify the IP address for RPC command. "
411 "Format: <ip-address>[':'<port-number>]")(
413 po::value<std::uint16_t>(),
414 "DEPRECATED: include with rpc_ip instead. "
415 "Specify the port number for RPC command.");
418 po::options_description test(
"Unit Test Options");
421 "Suppress test suite messages, "
422 "including suite/case name (at start) and test log messages.")(
424 po::value<std::string>()->implicit_value(
""),
425 "Perform unit tests. The optional argument specifies one or "
426 "more comma-separated selectors. Each selector specifies a suite name, "
427 "full-name (lib.module.suite), module, or library "
431 po::value<std::string>()->implicit_value(
""),
432 "Supplies an argument string to unit tests. If provided, this argument "
433 "is made available to each suite that runs. Interpretation of the "
434 "argument is handled individually by any suite that accesses it -- "
435 "as such, it typically only make sense to provide this when running "
438 "Use IPv6 localhost when running unittests (default is IPv4).")(
440 "Force unit test log message output. Only useful in combination with "
441 "--quiet, in which case log messages will print but suite/case names "
444 po::value<std::size_t>(),
445 "Number of unittest jobs to run in parallel (child processes).");
446 #endif // ENABLE_TESTS
450 po::options_description hidden(
"Hidden Options");
451 hidden.add_options()(
453 po::value<vector<string>>(),
454 "Specify rpc command and parameters. This option must be repeated "
455 "for each command/param. Positional parameters also serve this "
457 "so this option is not needed for users")
460 "For internal use only when spawning child unit test processes.")
462 (
"unittest",
"Disabled in this build.")(
463 "unittest-child",
"Disabled in this build.")
465 (
"fg",
"Deprecated: server always in foreground mode.");
468 po::positional_options_description p;
469 p.add(
"parameters", -1);
471 po::options_description
all;
477 #endif // ENABLE_TESTS
480 po::options_description desc;
486 #endif // ENABLE_TESTS
493 po::command_line_parser(argc, argv)
507 if (vm.count(
"help"))
513 if (vm.count(
"version"))
521 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
531 if (vm.count(
"unittest"))
535 if (vm.count(
"unittest-arg"))
539 bool unittestChild =
false;
540 if (vm.count(
"unittest-jobs"))
541 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
542 unittestChild = bool(vm.count(
"unittest-child"));
545 vm[
"unittest"].as<std::string>(),
547 bool(vm.count(
"quiet")),
548 bool(vm.count(
"unittest-log")),
550 bool(vm.count(
"unittest-ipv6")),
557 if (vm.count(
"unittest-jobs"))
560 std::cerr <<
"rippled: '--unittest-jobs' specified without "
562 std::cerr <<
"To run the unit tests the '--unittest' option must "
567 #endif // ENABLE_TESTS
569 auto config = std::make_unique<Config>();
577 bool(vm.count(
"quiet")),
578 bool(vm.count(
"silent")),
579 bool(vm.count(
"standalone")));
581 if (vm.count(
"vacuum"))
583 if (config->standalone())
585 std::cerr <<
"vacuum not applicable in standalone mode.\n";
597 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
605 if (vm.count(
"start"))
610 if (vm.count(
"startReporting"))
613 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
616 if (vm.count(
"reportingReadOnly"))
618 config->setReportingReadOnly(
true);
621 if (vm.count(
"import"))
622 config->doImport =
true;
624 if (vm.count(
"nodetoshard"))
625 config->nodeToShard =
true;
627 if (vm.count(
"ledger"))
629 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
630 if (vm.count(
"replay"))
635 else if (vm.count(
"ledgerfile"))
637 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
640 else if (vm.count(
"load") || config->FAST_LOAD)
645 if (vm.count(
"net") && !config->FAST_LOAD)
650 std::cerr <<
"Net and load/replay options are incompatible"
658 if (vm.count(
"valid"))
660 config->START_VALID =
true;
665 if (vm.count(
"rpc_ip"))
668 vm[
"rpc_ip"].as<std::string>());
676 if (endpoint->port() == 0)
678 std::cerr <<
"No port specified in rpc_ip.\n";
679 if (vm.count(
"rpc_port"))
681 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
685 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
686 if (endpoint->port() == 0)
699 config->rpc_ip = std::move(*endpoint);
702 if (vm.count(
"quorum"))
706 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
714 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
724 if (vm.count(
"quiet"))
726 else if (vm.count(
"verbose"))
729 auto logs = std::make_unique<Logs>(thresh);
732 if (!vm.count(
"parameters"))
736 if (config->had_trailing_comments())
738 JLOG(logs->journal(
"Application").warn())
739 <<
"Trailing comments were seen in your config file. "
740 <<
"The treatment of inline/trailing comments has changed "
742 <<
"Any `#` characters NOT intended to delimit comments should "
744 <<
"preceded by a \\";
752 if (vm.count(
"debug"))
758 std::move(config), std::move(logs), std::move(timeKeeper));
766 app->fdRequired(), app->logs().journal(
"Application")))
787 main(
int argc,
char** argv)
807 atexit(&google::protobuf::ShutdownProtobufLibrary);
809 return ripple::run(argc, argv);