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/contract.h>
26 #include <ripple/beast/clock/basic_seconds_clock.h>
27 #include <ripple/beast/core/CurrentThreadName.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>] [strict]\n"
129 " account_info <account>|<seed>|<pass_phrase>|<key> [<ledger>] "
131 " account_lines <account> <account>|\"\" [<ledger>]\n"
132 " account_channels <account> <account>|\"\" [<ledger>]\n"
133 " account_objects <account> [<ledger>] [strict]\n"
134 " account_offers <account>|<account_public_key> [<ledger>] "
136 " account_tx accountID [ledger_min [ledger_max [limit "
137 "[offset]]]] [binary] [count] [descending]\n"
138 " book_changes [<ledger hash|id>]\n"
139 " book_offers <taker_pays> <taker_gets> [<taker [<ledger> "
140 "[<limit> [<proof> [<marker>]]]]]\n"
141 " can_delete [<ledgerid>|<ledgerhash>|now|always|never]\n"
142 " channel_authorize <private_key> <channel_id> <drops>\n"
143 " channel_verify <public_key> <channel_id> <drops> <signature>\n"
144 " connect <ip> [<port>]\n"
146 " deposit_authorized <source_account> <destination_account> "
148 " download_shard [[<index> <url>]]\n"
149 " feature [<feature> [accept|reject]]\n"
150 " fetch_info [clear]\n"
151 " gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ "
154 " json <method> <json>\n"
155 " ledger [<id>|current|closed|validated] [full]\n"
160 " ledger_request <ledger>\n"
161 " log_level [[<partition>] <severity>]\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"
183 " validator_list_sites\n"
185 " wallet_propose [<passphrase>]\n";
200 explicit multi_selector(
std::string const& patterns =
"")
203 boost::split(v, patterns, boost::algorithm::is_any_of(
","));
207 if (selectors_.empty() || !s.empty())
208 selectors_.emplace_back(
209 beast::unit_test::selector::automatch, s);
214 operator()(beast::unit_test::suite_info
const& s)
216 for (
auto& sel : selectors_)
225 return selectors_.size();
233 template <
class Runner>
235 anyMissing(Runner& runner, multi_selector
const& pred)
237 if (runner.tests() == 0)
239 runner.add_failures(1);
243 if (runner.suites() < pred.size())
245 auto const missing = pred.size() - runner.suites();
246 runner.add_failures(missing);
248 <<
" filters did not match any existing test suites"
272 if (!child && num_jobs == 1)
277 child_runner.arg(argument);
278 multi_selector pred(pattern);
279 auto const any_failed =
280 child_runner.run_multi(pred) || anyMissing(child_runner, pred);
295 for (
int i = 1; i < argc; ++i)
302 boost::process::exe = exe_name, boost::process::args = args);
304 int bad_child_exits = 0;
305 int terminated_child_exits = 0;
306 for (
auto& c : children)
318 ++terminated_child_exits;
323 anyMissing(parent_runner, multi_selector(pattern));
325 if (parent_runner.
any_failed() || bad_child_exits)
333 runner.arg(argument);
334 auto const anyFailed = runner.run_multi(multi_selector(pattern));
342 #endif // ENABLE_TESTS
346 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.")(
373 po::value<std::size_t>(),
374 "Override the minimum validation quorum.")(
375 "reportingReadOnly",
"Run in read-only reporting mode")(
376 "silent",
"No output to the console after startup.")(
377 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
378 "version",
"Display the build version.");
380 po::options_description
data(
"Ledger/Data Options");
381 data.add_options()(
"import", importText.
c_str())(
383 po::value<std::string>(),
384 "Load the specified ledger and start from the value given.")(
386 po::value<std::string>(),
387 "Load the specified ledger file.")(
388 "load",
"Load the current ledger from the local DB.")(
389 "net",
"Get the initial ledger from the network.")(
390 "nodetoshard",
"Import node store into shards")(
391 "replay",
"Replay a ledger close.")(
392 "start",
"Start from a fresh Ledger.")(
394 po::value<std::string>(),
395 "Start reporting from a fresh Ledger.")(
396 "vacuum",
"VACUUM the transaction db.")(
397 "valid",
"Consider the initial ledger a valid network ledger.");
399 po::options_description rpc(
"RPC Client Options");
402 "Perform rpc command - see below for available commands. "
403 "This is assumed if any positional parameters are provided.")(
405 po::value<std::string>(),
406 "Specify the IP address for RPC command. "
407 "Format: <ip-address>[':'<port-number>]")(
409 po::value<std::uint16_t>(),
410 "DEPRECATED: include with rpc_ip instead. "
411 "Specify the port number for RPC command.");
414 po::options_description test(
"Unit Test Options");
417 "Suppress test suite messages, "
418 "including suite/case name (at start) and test log messages.")(
420 po::value<std::string>()->implicit_value(
""),
421 "Perform unit tests. The optional argument specifies one or "
422 "more comma-separated selectors. Each selector specifies a suite name, "
423 "full-name (lib.module.suite), module, or library "
427 po::value<std::string>()->implicit_value(
""),
428 "Supplies an argument string to unit tests. If provided, this argument "
429 "is made available to each suite that runs. Interpretation of the "
430 "argument is handled individually by any suite that accesses it -- "
431 "as such, it typically only make sense to provide this when running "
434 "Use IPv6 localhost when running unittests (default is IPv4).")(
436 "Force unit test log message output. Only useful in combination with "
437 "--quiet, in which case log messages will print but suite/case names "
440 po::value<std::size_t>(),
441 "Number of unittest jobs to run in parallel (child processes).");
442 #endif // ENABLE_TESTS
446 po::options_description hidden(
"Hidden Options");
447 hidden.add_options()(
449 po::value<vector<string>>(),
450 "Specify rpc command and parameters. This option must be repeated "
451 "for each command/param. Positional parameters also serve this "
453 "so this option is not needed for users")
456 "For internal use only when spawning child unit test processes.")
458 (
"unittest",
"Disabled in this build.")(
459 "unittest-child",
"Disabled in this build.")
461 (
"fg",
"Deprecated: server always in foreground mode.");
464 po::positional_options_description p;
465 p.add(
"parameters", -1);
467 po::options_description
all;
473 #endif // ENABLE_TESTS
476 po::options_description desc;
482 #endif // ENABLE_TESTS
489 po::command_line_parser(argc, argv)
503 if (vm.count(
"help"))
509 if (vm.count(
"version"))
517 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
527 if (vm.count(
"unittest"))
531 if (vm.count(
"unittest-arg"))
535 bool unittestChild =
false;
536 if (vm.count(
"unittest-jobs"))
537 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
538 unittestChild = bool(vm.count(
"unittest-child"));
541 vm[
"unittest"].as<std::string>(),
543 bool(vm.count(
"quiet")),
544 bool(vm.count(
"unittest-log")),
546 bool(vm.count(
"unittest-ipv6")),
553 if (vm.count(
"unittest-jobs"))
556 std::cerr <<
"rippled: '--unittest-jobs' specified without "
558 std::cerr <<
"To run the unit tests the '--unittest' option must "
563 #endif // ENABLE_TESTS
565 auto config = std::make_unique<Config>();
573 bool(vm.count(
"quiet")),
574 bool(vm.count(
"silent")),
575 bool(vm.count(
"standalone")));
577 if (vm.count(
"vacuum"))
579 if (config->standalone())
581 std::cerr <<
"vacuum not applicable in standalone mode.\n";
593 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
601 if (vm.count(
"start"))
606 if (vm.count(
"startReporting"))
609 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
612 if (vm.count(
"reportingReadOnly"))
614 config->setReportingReadOnly(
true);
617 if (vm.count(
"import"))
618 config->doImport =
true;
620 if (vm.count(
"nodetoshard"))
621 config->nodeToShard =
true;
623 if (vm.count(
"ledger"))
625 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
626 if (vm.count(
"replay"))
631 else if (vm.count(
"ledgerfile"))
633 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
636 else if (vm.count(
"load") || config->FAST_LOAD)
641 if (vm.count(
"net") && !config->FAST_LOAD)
646 std::cerr <<
"Net and load/replay options are incompatible"
654 if (vm.count(
"valid"))
656 config->START_VALID =
true;
661 if (vm.count(
"rpc_ip"))
664 vm[
"rpc_ip"].as<std::string>());
672 if (endpoint->port() == 0)
674 std::cerr <<
"No port specified in rpc_ip.\n";
675 if (vm.count(
"rpc_port"))
677 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
681 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
682 if (endpoint->port() == 0)
695 config->rpc_ip = std::move(*endpoint);
698 if (vm.count(
"quorum"))
702 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
710 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
720 if (vm.count(
"quiet"))
722 else if (vm.count(
"verbose"))
725 auto logs = std::make_unique<Logs>(thresh);
728 if (!vm.count(
"parameters"))
732 if (config->had_trailing_comments())
734 JLOG(logs->journal(
"Application").warn())
735 <<
"Trailing comments were seen in your config file. "
736 <<
"The treatment of inline/trailing comments has changed "
738 <<
"Any `#` characters NOT intended to delimit comments should "
740 <<
"preceded by a \\";
748 if (vm.count(
"debug"))
754 std::move(config), std::move(logs), std::move(timeKeeper));
762 app->fdRequired(), app->logs().journal(
"Application")))
783 main(
int argc,
char** argv)
803 atexit(&google::protobuf::ShutdownProtobufLibrary);
805 return ripple::run(argc, argv);