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 "full-name (lib.module.suite), module, or library "
438 po::value<std::string>()->implicit_value(
""),
439 "Supplies an argument string to unit tests. If provided, this argument "
440 "is made available to each suite that runs. Interpretation of the "
441 "argument is handled individually by any suite that accesses it -- "
442 "as such, it typically only make sense to provide this when running "
445 "Use IPv6 localhost when running unittests (default is IPv4).")(
447 "Force unit test log message output. Only useful in combination with "
448 "--quiet, in which case log messages will print but suite/case names "
451 po::value<std::size_t>(),
452 "Number of unittest jobs to run in parallel (child processes).");
453 #endif // ENABLE_TESTS
457 po::options_description hidden(
"Hidden Options");
458 hidden.add_options()(
460 po::value<vector<string>>(),
461 "Specify rpc command and parameters. This option must be repeated "
462 "for each command/param. Positional parameters also serve this "
464 "so this option is not needed for users")
467 "For internal use only when spawning child unit test processes.")
469 (
"unittest",
"Disabled in this build.")(
470 "unittest-child",
"Disabled in this build.")
472 (
"fg",
"Deprecated: server always in foreground mode.");
475 po::positional_options_description p;
476 p.add(
"parameters", -1);
478 po::options_description
all;
484 #endif // ENABLE_TESTS
487 po::options_description desc;
493 #endif // ENABLE_TESTS
500 po::command_line_parser(argc, argv)
514 if (vm.count(
"help"))
520 if (vm.count(
"version"))
528 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
538 if (vm.count(
"unittest"))
542 if (vm.count(
"unittest-arg"))
546 bool unittestChild =
false;
547 if (vm.count(
"unittest-jobs"))
548 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
549 unittestChild = bool(vm.count(
"unittest-child"));
552 vm[
"unittest"].as<std::string>(),
554 bool(vm.count(
"quiet")),
555 bool(vm.count(
"unittest-log")),
557 bool(vm.count(
"unittest-ipv6")),
564 if (vm.count(
"unittest-jobs"))
567 std::cerr <<
"rippled: '--unittest-jobs' specified without "
569 std::cerr <<
"To run the unit tests the '--unittest' option must "
574 #endif // ENABLE_TESTS
576 auto config = std::make_unique<Config>();
584 bool(vm.count(
"quiet")),
585 bool(vm.count(
"silent")),
586 bool(vm.count(
"standalone")));
588 if (vm.count(
"vacuum"))
590 if (config->standalone())
592 std::cerr <<
"vacuum not applicable in standalone mode.\n";
604 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
612 if (vm.contains(
"force_ledger_present_range"))
620 vm[
"force_ledger_present_range"].as<std::string>(),
621 boost::algorithm::is_any_of(
","));
623 for (
auto& s : strVec)
637 "Invalid force_ledger_present_range parameter");
639 config->FORCED_LEDGER_RANGE_PRESENT.emplace(r[0], r[1]);
644 "Invalid force_ledger_present_range parameter");
649 std::cerr <<
"invalid 'force_ledger_present_range' parameter. The "
650 "parameter must be two numbers separated by a comma. "
651 "The first number must be <= the second."
657 if (vm.count(
"start"))
662 if (vm.count(
"startReporting"))
665 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
668 if (vm.count(
"reportingReadOnly"))
670 config->setReportingReadOnly(
true);
673 if (vm.count(
"import"))
674 config->doImport =
true;
676 if (vm.count(
"nodetoshard"))
677 config->nodeToShard =
true;
679 if (vm.count(
"ledger"))
681 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
682 if (vm.count(
"replay"))
687 else if (vm.count(
"ledgerfile"))
689 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
692 else if (vm.count(
"load") || config->FAST_LOAD)
697 if (vm.count(
"net") && !config->FAST_LOAD)
702 std::cerr <<
"Net and load/replay options are incompatible"
710 if (vm.count(
"valid"))
712 config->START_VALID =
true;
717 if (vm.count(
"rpc_ip"))
720 vm[
"rpc_ip"].as<std::string>());
728 if (endpoint->port() == 0)
730 std::cerr <<
"No port specified in rpc_ip.\n";
731 if (vm.count(
"rpc_port"))
733 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
737 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
738 if (endpoint->port() == 0)
751 config->rpc_ip = std::move(*endpoint);
754 if (vm.count(
"quorum"))
758 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
766 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
776 if (vm.count(
"quiet"))
778 else if (vm.count(
"verbose"))
781 auto logs = std::make_unique<Logs>(thresh);
784 if (!vm.count(
"parameters"))
788 if (config->had_trailing_comments())
790 JLOG(logs->journal(
"Application").warn())
791 <<
"Trailing comments were seen in your config file. "
792 <<
"The treatment of inline/trailing comments has changed "
794 <<
"Any `#` characters NOT intended to delimit comments should "
796 <<
"preceded by a \\";
804 if (vm.count(
"debug"))
808 std::move(config), std::move(logs), std::make_unique<TimeKeeper>());
816 app->fdRequired(), app->logs().journal(
"Application")))
837 main(
int argc,
char** argv)
857 atexit(&google::protobuf::ShutdownProtobufLibrary);
859 return ripple::run(argc, argv);