20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/main/DBInit.h>
22 #include <ripple/app/rdb/RelationalDBInterface_global.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 <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_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 " node_to_shard [status|start|stop]\n"
166 " peer_reservations_add <public_key> [<description>]\n"
167 " peer_reservations_del <public_key>\n"
168 " peer_reservations_list\n"
170 " ripple_path_find <json> [<ledger>]\n"
171 " server_info [counters]\n"
172 " server_state [counters]\n"
173 " sign <private_key> <tx_json> [offline]\n"
174 " sign_for <signer_address> <signer_private_key> <tx_json> "
177 " submit <tx_blob>|[<private_key> <tx_json>]\n"
178 " submit_multisigned <tx_json>\n"
180 " validation_create [<seed>|<pass_phrase>|<key>]\n"
182 " validator_list_sites\n"
184 " wallet_propose [<passphrase>]\n";
199 explicit multi_selector(
std::string const& patterns =
"")
202 boost::split(v, patterns, boost::algorithm::is_any_of(
","));
206 if (selectors_.empty() || !s.empty())
207 selectors_.emplace_back(
208 beast::unit_test::selector::automatch, s);
213 operator()(beast::unit_test::suite_info
const& s)
215 for (
auto& sel : selectors_)
224 return selectors_.size();
232 template <
class Runner>
234 anyMissing(Runner& runner, multi_selector
const& pred)
236 if (runner.tests() == 0)
238 runner.add_failures(1);
242 if (runner.suites() < pred.size())
244 auto const missing = pred.size() - runner.suites();
245 runner.add_failures(missing);
247 <<
" filters did not match any existing test suites"
271 if (!child && num_jobs == 1)
276 child_runner.arg(argument);
277 multi_selector pred(pattern);
278 auto const any_failed =
279 child_runner.run_multi(pred) || anyMissing(child_runner, pred);
294 for (
int i = 1; i < argc; ++i)
301 boost::process::exe = exe_name, boost::process::args = args);
303 int bad_child_exits = 0;
304 int terminated_child_exits = 0;
305 for (
auto& c : children)
317 ++terminated_child_exits;
322 anyMissing(parent_runner, multi_selector(pattern));
324 if (parent_runner.
any_failed() || bad_child_exits)
332 runner.arg(argument);
333 auto const anyFailed = runner.run_multi(multi_selector(pattern));
341 #endif // ENABLE_TESTS
345 run(
int argc,
char** argv)
352 po::variables_map vm;
356 importText +=
"Import an existing node database (specified in the [";
358 importText +=
"] configuration file section) into the current ";
359 importText +=
"node database (specified in the [";
361 importText +=
"] configuration file section).";
366 po::options_description gen(
"General Options");
368 "conf", po::value<std::string>(),
"Specify the configuration file.")(
369 "debug",
"Enable normally suppressed debug logging")(
370 "help,h",
"Display this message.")(
372 po::value<std::size_t>(),
373 "Override the minimum validation quorum.")(
374 "reportingReadOnly",
"Run in read-only reporting mode")(
375 "silent",
"No output to the console after startup.")(
376 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
377 "version",
"Display the build version.");
379 po::options_description
data(
"Ledger/Data Options");
380 data.add_options()(
"import", importText.
c_str())(
382 po::value<std::string>(),
383 "Load the specified ledger and start from the value given.")(
385 po::value<std::string>(),
386 "Load the specified ledger file.")(
387 "load",
"Load the current ledger from the local DB.")(
388 "net",
"Get the initial ledger from the network.")(
389 "nodetoshard",
"Import node store into shards")(
390 "replay",
"Replay a ledger close.")(
391 "start",
"Start from a fresh Ledger.")(
393 po::value<std::string>(),
394 "Start reporting from a fresh Ledger.")(
395 "vacuum",
"VACUUM the transaction db.")(
396 "valid",
"Consider the initial ledger a valid network ledger.");
398 po::options_description rpc(
"RPC Client Options");
401 "Perform rpc command - see below for available commands. "
402 "This is assumed if any positional parameters are provided.")(
404 po::value<std::string>(),
405 "Specify the IP address for RPC command. "
406 "Format: <ip-address>[':'<port-number>]")(
408 po::value<std::uint16_t>(),
409 "DEPRECATED: include with rpc_ip instead. "
410 "Specify the port number for RPC command.");
413 po::options_description test(
"Unit Test Options");
416 "Suppress test suite messages, "
417 "including suite/case name (at start) and test log messages.")(
419 po::value<std::string>()->implicit_value(
""),
420 "Perform unit tests. The optional argument specifies one or "
421 "more comma-separated selectors. Each selector specifies a suite name, "
422 "full-name (lib.module.suite), module, or library "
426 po::value<std::string>()->implicit_value(
""),
427 "Supplies an argument string to unit tests. If provided, this argument "
428 "is made available to each suite that runs. Interpretation of the "
429 "argument is handled individually by any suite that accesses it -- "
430 "as such, it typically only make sense to provide this when running "
433 "Use IPv6 localhost when running unittests (default is IPv4).")(
435 "Force unit test log message output. Only useful in combination with "
436 "--quiet, in which case log messages will print but suite/case names "
439 po::value<std::size_t>(),
440 "Number of unittest jobs to run in parallel (child processes).");
441 #endif // ENABLE_TESTS
445 po::options_description hidden(
"Hidden Options");
446 hidden.add_options()(
448 po::value<vector<string>>(),
449 "Specify rpc command and parameters. This option must be repeated "
450 "for each command/param. Positional parameters also serve this "
452 "so this option is not needed for users")
455 "For internal use only when spawning child unit test processes.")
457 (
"unittest",
"Disabled in this build.")(
458 "unittest-child",
"Disabled in this build.")
460 (
"fg",
"Deprecated: server always in foreground mode.");
463 po::positional_options_description p;
464 p.add(
"parameters", -1);
466 po::options_description
all;
472 #endif // ENABLE_TESTS
475 po::options_description desc;
481 #endif // ENABLE_TESTS
488 po::command_line_parser(argc, argv)
502 if (vm.count(
"help"))
508 if (vm.count(
"version"))
516 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
526 if (vm.count(
"unittest"))
530 if (vm.count(
"unittest-arg"))
534 bool unittestChild =
false;
535 if (vm.count(
"unittest-jobs"))
536 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
537 unittestChild = bool(vm.count(
"unittest-child"));
540 vm[
"unittest"].as<std::string>(),
542 bool(vm.count(
"quiet")),
543 bool(vm.count(
"unittest-log")),
545 bool(vm.count(
"unittest-ipv6")),
552 if (vm.count(
"unittest-jobs"))
555 std::cerr <<
"rippled: '--unittest-jobs' specified without "
557 std::cerr <<
"To run the unit tests the '--unittest' option must "
562 #endif // ENABLE_TESTS
564 auto config = std::make_unique<Config>();
572 bool(vm.count(
"quiet")),
573 bool(vm.count(
"silent")),
574 bool(vm.count(
"standalone")));
576 if (vm.count(
"vacuum"))
578 if (config->standalone())
580 std::cerr <<
"vacuum not applicable in standalone mode.\n";
592 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
600 if (vm.count(
"start"))
605 if (vm.count(
"startReporting"))
608 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
611 if (vm.count(
"reportingReadOnly"))
613 config->setReportingReadOnly(
true);
616 if (vm.count(
"import"))
617 config->doImport =
true;
619 if (vm.count(
"nodetoshard"))
620 config->nodeToShard =
true;
622 if (vm.count(
"ledger"))
624 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
625 if (vm.count(
"replay"))
630 else if (vm.count(
"ledgerfile"))
632 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
635 else if (vm.count(
"load") || config->FAST_LOAD)
640 if (vm.count(
"net") && !config->FAST_LOAD)
645 std::cerr <<
"Net and load/replay options are incompatible"
653 if (vm.count(
"valid"))
655 config->START_VALID =
true;
660 if (vm.count(
"rpc_ip"))
663 vm[
"rpc_ip"].as<std::string>());
671 if (endpoint->port() == 0)
673 std::cerr <<
"No port specified in rpc_ip.\n";
674 if (vm.count(
"rpc_port"))
676 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
680 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
681 if (endpoint->port() == 0)
694 config->rpc_ip = std::move(*endpoint);
697 if (vm.count(
"quorum"))
701 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
709 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
719 if (vm.count(
"quiet"))
721 else if (vm.count(
"verbose"))
724 auto logs = std::make_unique<Logs>(thresh);
727 if (!vm.count(
"parameters"))
731 if (config->had_trailing_comments())
733 JLOG(logs->journal(
"Application").warn())
734 <<
"Trailing comments were seen in your config file. "
735 <<
"The treatment of inline/trailing comments has changed "
737 <<
"Any `#` characters NOT intended to delimit comments should "
739 <<
"preceded by a \\";
747 if (vm.count(
"debug"))
753 std::move(config), std::move(logs), std::move(timeKeeper));
761 app->fdRequired(), app->logs().journal(
"Application")))
782 main(
int argc,
char** argv)
802 atexit(&google::protobuf::ShutdownProtobufLibrary);
804 return ripple::run(argc, argv);