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_index_min [ledger_index_max "
139 " book_changes [<ledger hash|id>]\n"
140 " book_offers <taker_pays> <taker_gets> [<taker [<ledger> "
141 "[<limit> [<proof> [<marker>]]]]]\n"
142 " can_delete [<ledgerid>|<ledgerhash>|now|always|never]\n"
143 " channel_authorize <private_key> <channel_id> <drops>\n"
144 " channel_verify <public_key> <channel_id> <drops> <signature>\n"
145 " connect <ip> [<port>]\n"
147 " deposit_authorized <source_account> <destination_account> "
149 " download_shard [[<index> <url>]]\n"
150 " feature [<feature> [accept|reject]]\n"
151 " fetch_info [clear]\n"
152 " gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ "
155 " json <method> <json>\n"
156 " ledger [<id>|current|closed|validated] [full]\n"
161 " ledger_request <ledger>\n"
162 " log_level [[<partition>] <severity>]\n"
164 " manifest <public_key>\n"
165 " node_to_shard [status|start|stop]\n"
169 " peer_reservations_add <public_key> [<description>]\n"
170 " peer_reservations_del <public_key>\n"
171 " peer_reservations_list\n"
173 " ripple_path_find <json> [<ledger>]\n"
174 " server_info [counters]\n"
175 " server_state [counters]\n"
176 " sign <private_key> <tx_json> [offline]\n"
177 " sign_for <signer_address> <signer_private_key> <tx_json> "
180 " submit <tx_blob>|[<private_key> <tx_json>]\n"
181 " submit_multisigned <tx_json>\n"
183 " validation_create [<seed>|<pass_phrase>|<key>]\n"
186 " validator_list_sites\n"
188 " wallet_propose [<passphrase>]\n";
203 explicit multi_selector(
std::string const& patterns =
"")
206 boost::split(v, patterns, boost::algorithm::is_any_of(
","));
210 if (selectors_.empty() || !s.empty())
211 selectors_.emplace_back(
212 beast::unit_test::selector::automatch, s);
217 operator()(beast::unit_test::suite_info
const& s)
219 for (
auto& sel : selectors_)
228 return selectors_.size();
236 template <
class Runner>
238 anyMissing(Runner& runner, multi_selector
const& pred)
240 if (runner.tests() == 0)
242 runner.add_failures(1);
246 if (runner.suites() < pred.size())
248 auto const missing = pred.size() - runner.suites();
249 runner.add_failures(missing);
251 <<
" filters did not match any existing test suites"
275 if (!child && num_jobs == 1)
280 child_runner.arg(argument);
281 multi_selector pred(pattern);
282 auto const any_failed =
283 child_runner.run_multi(pred) || anyMissing(child_runner, pred);
298 for (
int i = 1; i < argc; ++i)
305 boost::process::exe = exe_name, boost::process::args = args);
307 int bad_child_exits = 0;
308 int terminated_child_exits = 0;
309 for (
auto& c : children)
321 ++terminated_child_exits;
326 anyMissing(parent_runner, multi_selector(pattern));
328 if (parent_runner.
any_failed() || bad_child_exits)
336 runner.arg(argument);
337 auto const anyFailed = runner.run_multi(multi_selector(pattern));
345 #endif // ENABLE_TESTS
349 run(
int argc,
char** argv)
356 po::variables_map vm;
360 importText +=
"Import an existing node database (specified in the [";
362 importText +=
"] configuration file section) into the current ";
363 importText +=
"node database (specified in the [";
365 importText +=
"] configuration file section).";
370 po::options_description gen(
"General Options");
372 "conf", po::value<std::string>(),
"Specify the configuration file.")(
373 "debug",
"Enable normally suppressed debug logging")(
374 "help,h",
"Display this message.")(
375 "newnodeid",
"Generate a new node identity for this server.")(
377 po::value<std::string>(),
378 "Specify the node identity for this server.")(
380 po::value<std::size_t>(),
381 "Override the minimum validation quorum.")(
382 "reportingReadOnly",
"Run in read-only reporting mode")(
383 "silent",
"No output to the console after startup.")(
384 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
385 "version",
"Display the build version.");
387 po::options_description
data(
"Ledger/Data Options");
388 data.add_options()(
"import", importText.
c_str())(
390 po::value<std::string>(),
391 "Load the specified ledger and start from the value given.")(
393 po::value<std::string>(),
394 "Load the specified ledger file.")(
395 "load",
"Load the current ledger from the local DB.")(
396 "net",
"Get the initial ledger from the network.")(
397 "nodetoshard",
"Import node store into shards")(
398 "replay",
"Replay a ledger close.")(
399 "start",
"Start from a fresh Ledger.")(
401 po::value<std::string>(),
402 "Start reporting from a fresh Ledger.")(
403 "vacuum",
"VACUUM the transaction db.")(
404 "valid",
"Consider the initial ledger a valid network ledger.");
406 po::options_description rpc(
"RPC Client Options");
409 "Perform rpc command - see below for available commands. "
410 "This is assumed if any positional parameters are provided.")(
412 po::value<std::string>(),
413 "Specify the IP address for RPC command. "
414 "Format: <ip-address>[':'<port-number>]")(
416 po::value<std::uint16_t>(),
417 "DEPRECATED: include with rpc_ip instead. "
418 "Specify the port number for RPC command.");
421 po::options_description test(
"Unit Test Options");
424 "Suppress test suite messages, "
425 "including suite/case name (at start) and test log messages.")(
427 po::value<std::string>()->implicit_value(
""),
428 "Perform unit tests. The optional argument specifies one or "
429 "more comma-separated selectors. Each selector specifies a suite name, "
430 "full-name (lib.module.suite), module, or library "
434 po::value<std::string>()->implicit_value(
""),
435 "Supplies an argument string to unit tests. If provided, this argument "
436 "is made available to each suite that runs. Interpretation of the "
437 "argument is handled individually by any suite that accesses it -- "
438 "as such, it typically only make sense to provide this when running "
441 "Use IPv6 localhost when running unittests (default is IPv4).")(
443 "Force unit test log message output. Only useful in combination with "
444 "--quiet, in which case log messages will print but suite/case names "
447 po::value<std::size_t>(),
448 "Number of unittest jobs to run in parallel (child processes).");
449 #endif // ENABLE_TESTS
453 po::options_description hidden(
"Hidden Options");
454 hidden.add_options()(
456 po::value<vector<string>>(),
457 "Specify rpc command and parameters. This option must be repeated "
458 "for each command/param. Positional parameters also serve this "
460 "so this option is not needed for users")
463 "For internal use only when spawning child unit test processes.")
465 (
"unittest",
"Disabled in this build.")(
466 "unittest-child",
"Disabled in this build.")
468 (
"fg",
"Deprecated: server always in foreground mode.");
471 po::positional_options_description p;
472 p.add(
"parameters", -1);
474 po::options_description
all;
480 #endif // ENABLE_TESTS
483 po::options_description desc;
489 #endif // ENABLE_TESTS
496 po::command_line_parser(argc, argv)
510 if (vm.count(
"help"))
516 if (vm.count(
"version"))
524 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
534 if (vm.count(
"unittest"))
538 if (vm.count(
"unittest-arg"))
542 bool unittestChild =
false;
543 if (vm.count(
"unittest-jobs"))
544 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
545 unittestChild = bool(vm.count(
"unittest-child"));
548 vm[
"unittest"].as<std::string>(),
550 bool(vm.count(
"quiet")),
551 bool(vm.count(
"unittest-log")),
553 bool(vm.count(
"unittest-ipv6")),
560 if (vm.count(
"unittest-jobs"))
563 std::cerr <<
"rippled: '--unittest-jobs' specified without "
565 std::cerr <<
"To run the unit tests the '--unittest' option must "
570 #endif // ENABLE_TESTS
572 auto config = std::make_unique<Config>();
580 bool(vm.count(
"quiet")),
581 bool(vm.count(
"silent")),
582 bool(vm.count(
"standalone")));
584 if (vm.count(
"vacuum"))
586 if (config->standalone())
588 std::cerr <<
"vacuum not applicable in standalone mode.\n";
600 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
608 if (vm.count(
"start"))
613 if (vm.count(
"startReporting"))
616 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
619 if (vm.count(
"reportingReadOnly"))
621 config->setReportingReadOnly(
true);
624 if (vm.count(
"import"))
625 config->doImport =
true;
627 if (vm.count(
"nodetoshard"))
628 config->nodeToShard =
true;
630 if (vm.count(
"ledger"))
632 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
633 if (vm.count(
"replay"))
638 else if (vm.count(
"ledgerfile"))
640 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
643 else if (vm.count(
"load") || config->FAST_LOAD)
648 if (vm.count(
"net") && !config->FAST_LOAD)
653 std::cerr <<
"Net and load/replay options are incompatible"
661 if (vm.count(
"valid"))
663 config->START_VALID =
true;
668 if (vm.count(
"rpc_ip"))
671 vm[
"rpc_ip"].as<std::string>());
679 if (endpoint->port() == 0)
681 std::cerr <<
"No port specified in rpc_ip.\n";
682 if (vm.count(
"rpc_port"))
684 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
688 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
689 if (endpoint->port() == 0)
702 config->rpc_ip = std::move(*endpoint);
705 if (vm.count(
"quorum"))
709 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
717 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
727 if (vm.count(
"quiet"))
729 else if (vm.count(
"verbose"))
732 auto logs = std::make_unique<Logs>(thresh);
735 if (!vm.count(
"parameters"))
739 if (config->had_trailing_comments())
741 JLOG(logs->journal(
"Application").warn())
742 <<
"Trailing comments were seen in your config file. "
743 <<
"The treatment of inline/trailing comments has changed "
745 <<
"Any `#` characters NOT intended to delimit comments should "
747 <<
"preceded by a \\";
755 if (vm.count(
"debug"))
761 std::move(config), std::move(logs), std::move(timeKeeper));
769 app->fdRequired(), app->logs().journal(
"Application")))
790 main(
int argc,
char** argv)
810 atexit(&google::protobuf::ShutdownProtobufLibrary);
812 return ripple::run(argc, argv);