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>]\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)
354 po::variables_map vm;
358 importText +=
"Import an existing node database (specified in the [";
360 importText +=
"] configuration file section) into the current ";
361 importText +=
"node database (specified in the [";
363 importText +=
"] configuration file section).";
368 po::options_description gen(
"General Options");
370 "conf", po::value<std::string>(),
"Specify the configuration file.")(
371 "debug",
"Enable normally suppressed debug logging")(
372 "help,h",
"Display this message.")(
373 "newnodeid",
"Generate a new node identity for this server.")(
375 po::value<std::string>(),
376 "Specify the node identity for this server.")(
378 po::value<std::size_t>(),
379 "Override the minimum validation quorum.")(
380 "reportingReadOnly",
"Run in read-only reporting mode")(
381 "silent",
"No output to the console after startup.")(
382 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
383 "version",
"Display the build version.");
385 po::options_description
data(
"Ledger/Data Options");
386 data.add_options()(
"import", importText.
c_str())(
388 po::value<std::string>(),
389 "Load the specified ledger and start from the value given.")(
391 po::value<std::string>(),
392 "Load the specified ledger file.")(
393 "load",
"Load the current ledger from the local DB.")(
394 "net",
"Get the initial ledger from the network.")(
395 "nodetoshard",
"Import node store into shards")(
396 "replay",
"Replay a ledger close.")(
397 "start",
"Start from a fresh Ledger.")(
399 po::value<std::string>(),
400 "Start reporting from a fresh Ledger.")(
401 "vacuum",
"VACUUM the transaction db.")(
402 "valid",
"Consider the initial ledger a valid network ledger.");
404 po::options_description rpc(
"RPC Client Options");
407 "Perform rpc command - see below for available commands. "
408 "This is assumed if any positional parameters are provided.")(
410 po::value<std::string>(),
411 "Specify the IP address for RPC command. "
412 "Format: <ip-address>[':'<port-number>]")(
414 po::value<std::uint16_t>(),
415 "DEPRECATED: include with rpc_ip instead. "
416 "Specify the port number for RPC command.");
419 po::options_description test(
"Unit Test Options");
422 "Suppress test suite messages, "
423 "including suite/case name (at start) and test log messages.")(
425 po::value<std::string>()->implicit_value(
""),
426 "Perform unit tests. The optional argument specifies one or "
427 "more comma-separated selectors. Each selector specifies a suite name, "
428 "full-name (lib.module.suite), module, or library "
432 po::value<std::string>()->implicit_value(
""),
433 "Supplies an argument string to unit tests. If provided, this argument "
434 "is made available to each suite that runs. Interpretation of the "
435 "argument is handled individually by any suite that accesses it -- "
436 "as such, it typically only make sense to provide this when running "
439 "Use IPv6 localhost when running unittests (default is IPv4).")(
441 "Force unit test log message output. Only useful in combination with "
442 "--quiet, in which case log messages will print but suite/case names "
445 po::value<std::size_t>(),
446 "Number of unittest jobs to run in parallel (child processes).");
447 #endif // ENABLE_TESTS
451 po::options_description hidden(
"Hidden Options");
452 hidden.add_options()(
454 po::value<vector<string>>(),
455 "Specify rpc command and parameters. This option must be repeated "
456 "for each command/param. Positional parameters also serve this "
458 "so this option is not needed for users")
461 "For internal use only when spawning child unit test processes.")
463 (
"unittest",
"Disabled in this build.")(
464 "unittest-child",
"Disabled in this build.")
466 (
"fg",
"Deprecated: server always in foreground mode.");
469 po::positional_options_description p;
470 p.add(
"parameters", -1);
472 po::options_description
all;
478 #endif // ENABLE_TESTS
481 po::options_description desc;
487 #endif // ENABLE_TESTS
494 po::command_line_parser(argc, argv)
508 if (vm.count(
"help"))
514 if (vm.count(
"version"))
522 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
532 if (vm.count(
"unittest"))
536 if (vm.count(
"unittest-arg"))
540 bool unittestChild =
false;
541 if (vm.count(
"unittest-jobs"))
542 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
543 unittestChild = bool(vm.count(
"unittest-child"));
546 vm[
"unittest"].as<std::string>(),
548 bool(vm.count(
"quiet")),
549 bool(vm.count(
"unittest-log")),
551 bool(vm.count(
"unittest-ipv6")),
558 if (vm.count(
"unittest-jobs"))
561 std::cerr <<
"rippled: '--unittest-jobs' specified without "
563 std::cerr <<
"To run the unit tests the '--unittest' option must "
568 #endif // ENABLE_TESTS
570 auto config = std::make_unique<Config>();
578 bool(vm.count(
"quiet")),
579 bool(vm.count(
"silent")),
580 bool(vm.count(
"standalone")));
582 if (vm.count(
"vacuum"))
584 if (config->standalone())
586 std::cerr <<
"vacuum not applicable in standalone mode.\n";
598 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
606 if (vm.count(
"start"))
611 if (vm.count(
"startReporting"))
614 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
617 if (vm.count(
"reportingReadOnly"))
619 config->setReportingReadOnly(
true);
622 if (vm.count(
"import"))
623 config->doImport =
true;
625 if (vm.count(
"nodetoshard"))
626 config->nodeToShard =
true;
628 if (vm.count(
"ledger"))
630 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
631 if (vm.count(
"replay"))
636 else if (vm.count(
"ledgerfile"))
638 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
641 else if (vm.count(
"load") || config->FAST_LOAD)
646 if (vm.count(
"net") && !config->FAST_LOAD)
651 std::cerr <<
"Net and load/replay options are incompatible"
659 if (vm.count(
"valid"))
661 config->START_VALID =
true;
666 if (vm.count(
"rpc_ip"))
669 vm[
"rpc_ip"].as<std::string>());
677 if (endpoint->port() == 0)
679 std::cerr <<
"No port specified in rpc_ip.\n";
680 if (vm.count(
"rpc_port"))
682 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
686 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
687 if (endpoint->port() == 0)
700 config->rpc_ip = std::move(*endpoint);
703 if (vm.count(
"quorum"))
707 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
715 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
725 if (vm.count(
"quiet"))
727 else if (vm.count(
"verbose"))
730 auto logs = std::make_unique<Logs>(thresh);
733 if (!vm.count(
"parameters"))
737 if (config->had_trailing_comments())
739 JLOG(logs->journal(
"Application").warn())
740 <<
"Trailing comments were seen in your config file. "
741 <<
"The treatment of inline/trailing comments has changed "
743 <<
"Any `#` characters NOT intended to delimit comments should "
745 <<
"preceded by a \\";
753 if (vm.count(
"debug"))
759 std::move(config), std::move(logs), std::move(timeKeeper));
767 app->fdRequired(), app->logs().journal(
"Application")))
788 main(
int argc,
char** argv)
808 atexit(&google::protobuf::ShutdownProtobufLibrary);
810 return ripple::run(argc, argv);