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_definitions [<hash>]\n"
173 " server_info [counters]\n"
174 " server_state [counters]\n"
175 " sign <private_key> <tx_json> [offline]\n"
176 " sign_for <signer_address> <signer_private_key> <tx_json> "
179 " submit <tx_blob>|[<private_key> <tx_json>]\n"
180 " submit_multisigned <tx_json>\n"
182 " validation_create [<seed>|<pass_phrase>|<key>]\n"
185 " validator_list_sites\n"
187 " wallet_propose [<passphrase>]\n";
202 explicit multi_selector(
std::string const& patterns =
"")
205 boost::split(v, patterns, boost::algorithm::is_any_of(
","));
209 if (selectors_.empty() || !s.empty())
210 selectors_.emplace_back(
211 beast::unit_test::selector::automatch, s);
216 operator()(beast::unit_test::suite_info
const& s)
218 for (
auto& sel : selectors_)
227 return selectors_.size();
235 template <
class Runner>
237 anyMissing(Runner& runner, multi_selector
const& pred)
239 if (runner.tests() == 0)
241 runner.add_failures(1);
245 if (runner.suites() < pred.size())
247 auto const missing = pred.size() - runner.suites();
248 runner.add_failures(missing);
250 <<
" filters did not match any existing test suites"
274 if (!child && num_jobs == 1)
279 child_runner.arg(argument);
280 multi_selector pred(pattern);
281 auto const any_failed =
282 child_runner.run_multi(pred) || anyMissing(child_runner, pred);
297 for (
int i = 1; i < argc; ++i)
304 boost::process::exe = exe_name, boost::process::args = args);
306 int bad_child_exits = 0;
307 int terminated_child_exits = 0;
308 for (
auto& c : children)
320 ++terminated_child_exits;
325 anyMissing(parent_runner, multi_selector(pattern));
327 if (parent_runner.
any_failed() || bad_child_exits)
335 runner.arg(argument);
336 auto const anyFailed = runner.run_multi(multi_selector(pattern));
344 #endif // ENABLE_TESTS
348 run(
int argc,
char** argv)
355 po::variables_map vm;
359 importText +=
"Import an existing node database (specified in the [";
361 importText +=
"] configuration file section) into the current ";
362 importText +=
"node database (specified in the [";
364 importText +=
"] configuration file section).";
369 po::options_description gen(
"General Options");
371 "conf", po::value<std::string>(),
"Specify the configuration file.")(
372 "debug",
"Enable normally suppressed debug logging")(
373 "help,h",
"Display this message.")(
374 "newnodeid",
"Generate a new node identity for this server.")(
376 po::value<std::string>(),
377 "Specify the node identity for this server.")(
379 po::value<std::size_t>(),
380 "Override the minimum validation quorum.")(
381 "reportingReadOnly",
"Run in read-only reporting mode")(
382 "silent",
"No output to the console after startup.")(
383 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")
385 (
"force_ledger_present_range",
386 po::value<std::string>(),
387 "Specify the range of present ledgers for testing purposes. Min and "
388 "max values are comma separated.")(
389 "version",
"Display the build version.");
391 po::options_description
data(
"Ledger/Data Options");
392 data.add_options()(
"import", importText.
c_str())(
394 po::value<std::string>(),
395 "Load the specified ledger and start from the value given.")(
397 po::value<std::string>(),
398 "Load the specified ledger file.")(
399 "load",
"Load the current ledger from the local DB.")(
400 "net",
"Get the initial ledger from the network.")(
401 "nodetoshard",
"Import node store into shards")(
402 "replay",
"Replay a ledger close.")(
403 "start",
"Start from a fresh Ledger.")(
405 po::value<std::string>(),
406 "Start reporting from a fresh Ledger.")(
407 "vacuum",
"VACUUM the transaction db.")(
408 "valid",
"Consider the initial ledger a valid network ledger.");
410 po::options_description rpc(
"RPC Client Options");
413 "Perform rpc command - see below for available commands. "
414 "This is assumed if any positional parameters are provided.")(
416 po::value<std::string>(),
417 "Specify the IP address for RPC command. "
418 "Format: <ip-address>[':'<port-number>]")(
420 po::value<std::uint16_t>(),
421 "DEPRECATED: include with rpc_ip instead. "
422 "Specify the port number for RPC command.");
425 po::options_description test(
"Unit Test Options");
428 "Suppress test suite messages, "
429 "including suite/case name (at start) and test log messages.")(
431 po::value<std::string>()->implicit_value(
""),
432 "Perform unit tests. The optional argument specifies one or "
433 "more comma-separated selectors. Each selector specifies a suite name, "
434 "suite name prefix, full-name (lib.module.suite), module, or library "
435 "(checked in that order).")(
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"))
807 std::move(config), std::move(logs), std::make_unique<TimeKeeper>());
815 app->fdRequired(), app->logs().journal(
"Application")))
836 main(
int argc,
char** argv)
856 atexit(&google::protobuf::ShutdownProtobufLibrary);
858 return ripple::run(argc, argv);