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.")
384 (
"force_ledger_present_range",
385 po::value<std::string>(),
386 "Specify the range of present ledgers for testing purposes. Min and "
387 "max values are comma separated.")(
388 "version",
"Display the build version.");
390 po::options_description
data(
"Ledger/Data Options");
391 data.add_options()(
"import", importText.
c_str())(
393 po::value<std::string>(),
394 "Load the specified ledger and start from the value given.")(
396 po::value<std::string>(),
397 "Load the specified ledger file.")(
398 "load",
"Load the current ledger from the local DB.")(
399 "net",
"Get the initial ledger from the network.")(
400 "nodetoshard",
"Import node store into shards")(
401 "replay",
"Replay a ledger close.")(
402 "start",
"Start from a fresh Ledger.")(
404 po::value<std::string>(),
405 "Start reporting from a fresh Ledger.")(
406 "vacuum",
"VACUUM the transaction db.")(
407 "valid",
"Consider the initial ledger a valid network ledger.");
409 po::options_description rpc(
"RPC Client Options");
412 "Perform rpc command - see below for available commands. "
413 "This is assumed if any positional parameters are provided.")(
415 po::value<std::string>(),
416 "Specify the IP address for RPC command. "
417 "Format: <ip-address>[':'<port-number>]")(
419 po::value<std::uint16_t>(),
420 "DEPRECATED: include with rpc_ip instead. "
421 "Specify the port number for RPC command.");
424 po::options_description test(
"Unit Test Options");
427 "Suppress test suite messages, "
428 "including suite/case name (at start) and test log messages.")(
430 po::value<std::string>()->implicit_value(
""),
431 "Perform unit tests. The optional argument specifies one or "
432 "more comma-separated selectors. Each selector specifies a suite name, "
433 "full-name (lib.module.suite), module, or library "
437 po::value<std::string>()->implicit_value(
""),
438 "Supplies an argument string to unit tests. If provided, this argument "
439 "is made available to each suite that runs. Interpretation of the "
440 "argument is handled individually by any suite that accesses it -- "
441 "as such, it typically only make sense to provide this when running "
444 "Use IPv6 localhost when running unittests (default is IPv4).")(
446 "Force unit test log message output. Only useful in combination with "
447 "--quiet, in which case log messages will print but suite/case names "
450 po::value<std::size_t>(),
451 "Number of unittest jobs to run in parallel (child processes).");
452 #endif // ENABLE_TESTS
456 po::options_description hidden(
"Hidden Options");
457 hidden.add_options()(
459 po::value<vector<string>>(),
460 "Specify rpc command and parameters. This option must be repeated "
461 "for each command/param. Positional parameters also serve this "
463 "so this option is not needed for users")
466 "For internal use only when spawning child unit test processes.")
468 (
"unittest",
"Disabled in this build.")(
469 "unittest-child",
"Disabled in this build.")
471 (
"fg",
"Deprecated: server always in foreground mode.");
474 po::positional_options_description p;
475 p.add(
"parameters", -1);
477 po::options_description
all;
483 #endif // ENABLE_TESTS
486 po::options_description desc;
492 #endif // ENABLE_TESTS
499 po::command_line_parser(argc, argv)
513 if (vm.count(
"help"))
519 if (vm.count(
"version"))
527 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
537 if (vm.count(
"unittest"))
541 if (vm.count(
"unittest-arg"))
545 bool unittestChild =
false;
546 if (vm.count(
"unittest-jobs"))
547 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
548 unittestChild = bool(vm.count(
"unittest-child"));
551 vm[
"unittest"].as<std::string>(),
553 bool(vm.count(
"quiet")),
554 bool(vm.count(
"unittest-log")),
556 bool(vm.count(
"unittest-ipv6")),
563 if (vm.count(
"unittest-jobs"))
566 std::cerr <<
"rippled: '--unittest-jobs' specified without "
568 std::cerr <<
"To run the unit tests the '--unittest' option must "
573 #endif // ENABLE_TESTS
575 auto config = std::make_unique<Config>();
583 bool(vm.count(
"quiet")),
584 bool(vm.count(
"silent")),
585 bool(vm.count(
"standalone")));
587 if (vm.count(
"vacuum"))
589 if (config->standalone())
591 std::cerr <<
"vacuum not applicable in standalone mode.\n";
603 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
611 if (vm.contains(
"force_ledger_present_range"))
619 vm[
"force_ledger_present_range"].as<std::string>(),
620 boost::algorithm::is_any_of(
","));
622 for (
auto& s : strVec)
636 "Invalid force_ledger_present_range parameter");
638 config->FORCED_LEDGER_RANGE_PRESENT.emplace(r[0], r[1]);
643 "Invalid force_ledger_present_range parameter");
648 std::cerr <<
"invalid 'force_ledger_present_range' parameter. The "
649 "parameter must be two numbers separated by a comma. "
650 "The first number must be <= the second."
656 if (vm.count(
"start"))
661 if (vm.count(
"startReporting"))
664 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
667 if (vm.count(
"reportingReadOnly"))
669 config->setReportingReadOnly(
true);
672 if (vm.count(
"import"))
673 config->doImport =
true;
675 if (vm.count(
"nodetoshard"))
676 config->nodeToShard =
true;
678 if (vm.count(
"ledger"))
680 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
681 if (vm.count(
"replay"))
686 else if (vm.count(
"ledgerfile"))
688 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
691 else if (vm.count(
"load") || config->FAST_LOAD)
696 if (vm.count(
"net") && !config->FAST_LOAD)
701 std::cerr <<
"Net and load/replay options are incompatible"
709 if (vm.count(
"valid"))
711 config->START_VALID =
true;
716 if (vm.count(
"rpc_ip"))
719 vm[
"rpc_ip"].as<std::string>());
727 if (endpoint->port() == 0)
729 std::cerr <<
"No port specified in rpc_ip.\n";
730 if (vm.count(
"rpc_port"))
732 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
736 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
737 if (endpoint->port() == 0)
750 config->rpc_ip = std::move(*endpoint);
753 if (vm.count(
"quorum"))
757 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
765 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
775 if (vm.count(
"quiet"))
777 else if (vm.count(
"verbose"))
780 auto logs = std::make_unique<Logs>(thresh);
783 if (!vm.count(
"parameters"))
787 if (config->had_trailing_comments())
789 JLOG(logs->journal(
"Application").warn())
790 <<
"Trailing comments were seen in your config file. "
791 <<
"The treatment of inline/trailing comments has changed "
793 <<
"Any `#` characters NOT intended to delimit comments should "
795 <<
"preceded by a \\";
803 if (vm.count(
"debug"))
809 std::move(config), std::move(logs), std::move(timeKeeper));
817 app->fdRequired(), app->logs().journal(
"Application")))
838 main(
int argc,
char** argv)
858 atexit(&google::protobuf::ShutdownProtobufLibrary);
860 return ripple::run(argc, argv);