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>
37 #include <beast/unit_test/match.hpp>
38 #include <test/unit_test/multi_runner.h>
40 #include <google/protobuf/stubs/common.h>
42 #include <boost/filesystem.hpp>
43 #include <boost/predef.h>
44 #include <boost/process.hpp>
45 #include <boost/program_options.hpp>
53 #include <sys/timeb.h>
54 #include <sys/types.h>
59 #if !BOOST_OS_LINUX && !BOOST_OS_WINDOWS && !BOOST_OS_MACOS
60 #error Supported platforms are: Linux, Windows and MacOS
64 #if (BOOST_OS_LINUX && (BOOST_OS_WINDOWS || BOOST_OS_MACOS)) || \
65 (BOOST_OS_MACOS && (BOOST_OS_WINDOWS || BOOST_OS_LINUX)) || \
66 (BOOST_OS_WINDOWS && (BOOST_OS_LINUX || BOOST_OS_MACOS))
67 #error Multiple supported platforms appear active at once
70 namespace po = boost::program_options;
83 if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
86 if (rl.rlim_cur == RLIM_INFINITY)
98 if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
105 j.
fatal() <<
"Insufficient number of file descriptors: " << needed
106 <<
" are needed, but only " <<
available <<
" are available.";
108 std::cerr <<
"Insufficient number of file descriptors: " << needed
110 <<
" are available.\n";
123 <<
systemName() <<
"d [options] <command> <params>\n"
126 " account_currencies <account> [<ledger>] [strict]\n"
127 " account_info <account>|<seed>|<pass_phrase>|<key> [<ledger>] "
129 " account_lines <account> <account>|\"\" [<ledger>]\n"
130 " account_channels <account> <account>|\"\" [<ledger>]\n"
131 " account_objects <account> [<ledger>] [strict]\n"
132 " account_offers <account>|<account_public_key> [<ledger>] "
134 " account_tx accountID [ledger_min [ledger_max [limit "
135 "[offset]]]] [binary] [count] [descending]\n"
136 " book_offers <taker_pays> <taker_gets> [<taker [<ledger> "
137 "[<limit> [<proof> [<marker>]]]]]\n"
138 " can_delete [<ledgerid>|<ledgerhash>|now|always|never]\n"
139 " channel_authorize <private_key> <channel_id> <drops>\n"
140 " channel_verify <public_key> <channel_id> <drops> <signature>\n"
141 " connect <ip> [<port>]\n"
143 " deposit_authorized <source_account> <destination_account> "
145 " download_shard [[<index> <url>]]\n"
146 " feature [<feature> [accept|reject]]\n"
147 " fetch_info [clear]\n"
148 " gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ "
151 " json <method> <json>\n"
152 " ledger [<id>|current|closed|validated] [full]\n"
157 " ledger_request <ledger>\n"
158 " log_level [[<partition>] <severity>]\n"
160 " nodetoshard_status\n"
164 " peer_reservations_add <public_key> [<description>]\n"
165 " peer_reservations_del <public_key>\n"
166 " peer_reservations_list\n"
168 " ripple_path_find <json> [<ledger>]\n"
169 " server_info [counters]\n"
170 " server_state [counters]\n"
171 " sign <private_key> <tx_json> [offline]\n"
172 " sign_for <signer_address> <signer_private_key> <tx_json> "
175 " submit <tx_blob>|[<private_key> <tx_json>]\n"
176 " submit_multisigned <tx_json>\n"
178 " validation_create [<seed>|<pass_phrase>|<key>]\n"
180 " validator_list_sites\n"
182 " wallet_propose [<passphrase>]\n";
196 explicit multi_selector(
std::string const& patterns =
"")
199 boost::split(v, patterns, boost::algorithm::is_any_of(
","));
203 if (selectors_.empty() || !s.empty())
204 selectors_.emplace_back(
205 beast::unit_test::selector::automatch, s);
210 operator()(beast::unit_test::suite_info
const& s)
212 for (
auto& sel : selectors_)
221 return selectors_.size();
229 template <
class Runner>
231 anyMissing(Runner& runner, multi_selector
const& pred)
233 if (runner.tests() == 0)
235 runner.add_failures(1);
239 if (runner.suites() < pred.size())
241 auto const missing = pred.size() - runner.suites();
242 runner.add_failures(missing);
244 <<
" filters did not match any existing test suites"
268 if (!child && num_jobs == 1)
273 child_runner.arg(argument);
274 multi_selector pred(pattern);
275 auto const any_failed =
276 child_runner.run_multi(pred) || anyMissing(child_runner, pred);
291 for (
int i = 1; i < argc; ++i)
298 boost::process::exe = exe_name, boost::process::args = args);
300 int bad_child_exits = 0;
301 int terminated_child_exits = 0;
302 for (
auto& c : children)
314 ++terminated_child_exits;
319 anyMissing(parent_runner, multi_selector(pattern));
321 if (parent_runner.
any_failed() || bad_child_exits)
329 runner.arg(argument);
330 auto const anyFailed = runner.run_multi(multi_selector(pattern));
341 run(
int argc,
char** argv)
348 po::variables_map vm;
352 importText +=
"Import an existing node database (specified in the [";
354 importText +=
"] configuration file section) into the current ";
355 importText +=
"node database (specified in the [";
357 importText +=
"] configuration file section).";
362 po::options_description gen(
"General Options");
364 "conf", po::value<std::string>(),
"Specify the configuration file.")(
365 "debug",
"Enable normally suppressed debug logging")(
366 "help,h",
"Display this message.")(
368 po::value<std::size_t>(),
369 "Override the minimum validation quorum.")(
370 "reportingReadOnly",
"Run in read-only reporting mode")(
371 "silent",
"No output to the console after startup.")(
372 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
373 "version",
"Display the build version.");
375 po::options_description
data(
"Ledger/Data Options");
376 data.add_options()(
"import", importText.
c_str())(
378 po::value<std::string>(),
379 "Load the specified ledger and start from the value given.")(
381 po::value<std::string>(),
382 "Load the specified ledger file.")(
383 "load",
"Load the current ledger from the local DB.")(
384 "net",
"Get the initial ledger from the network.")(
385 "nodetoshard",
"Import node store into shards")(
386 "replay",
"Replay a ledger close.")(
387 "start",
"Start from a fresh Ledger.")(
389 po::value<std::string>(),
390 "Start reporting from a fresh Ledger.")(
391 "vacuum",
"VACUUM the transaction db.")(
392 "valid",
"Consider the initial ledger a valid network ledger.");
394 po::options_description rpc(
"RPC Client Options");
397 "Perform rpc command - see below for available commands. "
398 "This is assumed if any positional parameters are provided.")(
400 po::value<std::string>(),
401 "Specify the IP address for RPC command. "
402 "Format: <ip-address>[':'<port-number>]")(
404 po::value<std::uint16_t>(),
405 "DEPRECATED: include with rpc_ip instead. "
406 "Specify the port number for RPC command.");
408 po::options_description test(
"Unit Test Options");
411 "Suppress test suite messages, "
412 "including suite/case name (at start) and test log messages.")(
414 po::value<std::string>()->implicit_value(
""),
415 "Perform unit tests. The optional argument specifies one or "
416 "more comma-separated selectors. Each selector specifies a suite name, "
417 "full-name (lib.module.suite), module, or library "
421 po::value<std::string>()->implicit_value(
""),
422 "Supplies an argument string to unit tests. If provided, this argument "
423 "is made available to each suite that runs. Interpretation of the "
424 "argument is handled individually by any suite that accesses it -- "
425 "as such, it typically only make sense to provide this when running "
428 "Use IPv6 localhost when running unittests (default is IPv4).")(
430 "Force unit test log message output. Only useful in combination with "
431 "--quiet, in which case log messages will print but suite/case names "
434 po::value<std::size_t>(),
435 "Number of unittest jobs to run in parallel (child processes).");
439 po::options_description hidden(
"Hidden Options");
440 hidden.add_options()(
442 po::value<vector<string>>(),
443 "Specify rpc command and parameters. This option must be repeated "
444 "for each command/param. Positional parameters also serve this "
446 "so this option is not needed for users")(
448 "For internal use only when spawning child unit test processes.")(
449 "fg",
"Deprecated: server always in foreground mode.");
452 po::positional_options_description p;
453 p.add(
"parameters", -1);
455 po::options_description
all;
456 all.add(gen).add(rpc).add(data).add(test).add(hidden);
458 po::options_description desc;
459 desc.add(gen).add(rpc).add(data).add(test);
465 po::command_line_parser(argc, argv)
479 if (vm.count(
"help"))
485 if (vm.count(
"version"))
495 if (vm.count(
"unittest"))
499 if (vm.count(
"unittest-arg"))
503 bool unittestChild =
false;
504 if (vm.count(
"unittest-jobs"))
505 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
506 unittestChild = bool(vm.count(
"unittest-child"));
509 vm[
"unittest"].as<std::string>(),
511 bool(vm.count(
"quiet")),
512 bool(vm.count(
"unittest-log")),
514 bool(vm.count(
"unittest-ipv6")),
521 if (vm.count(
"unittest-jobs"))
524 std::cerr <<
"rippled: '--unittest-jobs' specified without "
526 std::cerr <<
"To run the unit tests the '--unittest' option must "
532 auto config = std::make_unique<Config>();
540 bool(vm.count(
"quiet")),
541 bool(vm.count(
"silent")),
542 bool(vm.count(
"standalone")));
544 if (vm.count(
"vacuum"))
546 if (config->standalone())
548 std::cerr <<
"vacuum not applicable in standalone mode.\n";
560 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
568 if (vm.count(
"start"))
573 if (vm.count(
"startReporting"))
576 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
579 if (vm.count(
"reportingReadOnly"))
581 config->setReportingReadOnly(
true);
584 if (vm.count(
"import"))
585 config->doImport =
true;
587 if (vm.count(
"nodetoshard"))
588 config->nodeToShard =
true;
590 if (vm.count(
"ledger"))
592 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
593 if (vm.count(
"replay"))
598 else if (vm.count(
"ledgerfile"))
600 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
603 else if (vm.count(
"load"))
608 if (vm.count(
"valid"))
610 config->START_VALID =
true;
618 std::cerr <<
"Net and load/replay options are incompatible"
628 if (vm.count(
"rpc_ip"))
631 vm[
"rpc_ip"].as<std::string>());
639 if (endpoint->port() == 0)
641 std::cerr <<
"No port specified in rpc_ip.\n";
642 if (vm.count(
"rpc_port"))
644 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
648 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
649 if (endpoint->port() == 0)
662 config->rpc_ip = std::move(*endpoint);
665 if (vm.count(
"quorum"))
669 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
677 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
687 if (vm.count(
"quiet"))
689 else if (vm.count(
"verbose"))
692 auto logs = std::make_unique<Logs>(thresh);
695 if (!vm.count(
"parameters"))
699 if (config->had_trailing_comments())
701 JLOG(logs->journal(
"Application").warn())
702 <<
"Trailing comments were seen in your config file. "
703 <<
"The treatment of inline/trailing comments has changed "
705 <<
"Any `#` characters NOT intended to delimit comments should "
707 <<
"preceded by a \\";
715 if (vm.count(
"debug"))
721 std::move(config), std::move(logs), std::move(timeKeeper));
729 app->fdRequired(), app->logs().journal(
"Application")))
750 main(
int argc,
char** argv)
770 atexit(&google::protobuf::ShutdownProtobufLibrary);
772 return ripple::run(argc, argv);