20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/main/DBInit.h>
22 #include <ripple/basics/Log.h>
23 #include <ripple/basics/StringUtilities.h>
24 #include <ripple/basics/contract.h>
25 #include <ripple/beast/clock/basic_seconds_clock.h>
26 #include <ripple/beast/core/CurrentThreadName.h>
27 #include <ripple/core/Config.h>
28 #include <ripple/core/ConfigSections.h>
29 #include <ripple/core/DatabaseCon.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"
163 " peer_reservations_add <public_key> [<description>]\n"
164 " peer_reservations_del <public_key>\n"
165 " peer_reservations_list\n"
167 " ripple_path_find <json> [<ledger>]\n"
168 " server_info [counters]\n"
169 " server_state [counters]\n"
170 " sign <private_key> <tx_json> [offline]\n"
171 " sign_for <signer_address> <signer_private_key> <tx_json> "
174 " submit <tx_blob>|[<private_key> <tx_json>]\n"
175 " submit_multisigned <tx_json>\n"
177 " validation_create [<seed>|<pass_phrase>|<key>]\n"
179 " validator_list_sites\n"
181 " wallet_propose [<passphrase>]\n";
195 explicit multi_selector(
std::string const& patterns =
"")
198 boost::split(v, patterns, boost::algorithm::is_any_of(
","));
202 if (selectors_.empty() || !s.empty())
203 selectors_.emplace_back(
204 beast::unit_test::selector::automatch, s);
209 operator()(beast::unit_test::suite_info
const& s)
211 for (
auto& sel : selectors_)
220 return selectors_.size();
228 template <
class Runner>
230 anyMissing(Runner& runner, multi_selector
const& pred)
232 if (runner.tests() == 0)
234 runner.add_failures(1);
238 if (runner.suites() < pred.size())
240 auto const missing = pred.size() - runner.suites();
241 runner.add_failures(missing);
243 <<
" filters did not match any existing test suites"
267 if (!child && num_jobs == 1)
272 child_runner.arg(argument);
273 multi_selector pred(pattern);
274 auto const any_failed =
275 child_runner.run_multi(pred) || anyMissing(child_runner, pred);
290 for (
int i = 1; i < argc; ++i)
297 boost::process::exe = exe_name, boost::process::args = args);
299 int bad_child_exits = 0;
300 int terminated_child_exits = 0;
301 for (
auto& c : children)
313 ++terminated_child_exits;
318 anyMissing(parent_runner, multi_selector(pattern));
320 if (parent_runner.
any_failed() || bad_child_exits)
328 runner.arg(argument);
329 auto const anyFailed = runner.run_multi(multi_selector(pattern));
340 run(
int argc,
char** argv)
347 po::variables_map vm;
351 importText +=
"Import an existing node database (specified in the [";
353 importText +=
"] configuration file section) into the current ";
354 importText +=
"node database (specified in the [";
356 importText +=
"] configuration file section).";
361 po::options_description gen(
"General Options");
363 "conf", po::value<std::string>(),
"Specify the configuration file.")(
364 "debug",
"Enable normally suppressed debug logging")(
365 "help,h",
"Display this message.")(
367 po::value<std::size_t>(),
368 "Override the minimum validation quorum.")(
369 "reportingReadOnly",
"Run in read-only reporting mode")(
370 "silent",
"No output to the console after startup.")(
371 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
372 "version",
"Display the build version.");
374 po::options_description
data(
"Ledger/Data Options");
375 data.add_options()(
"import", importText.
c_str())(
377 po::value<std::string>(),
378 "Load the specified ledger and start from the value given.")(
380 po::value<std::string>(),
381 "Load the specified ledger file.")(
382 "load",
"Load the current ledger from the local DB.")(
383 "net",
"Get the initial ledger from the network.")(
384 "nodetoshard",
"Import node store into shards")(
385 "replay",
"Replay a ledger close.")(
386 "start",
"Start from a fresh Ledger.")(
388 po::value<std::string>(),
389 "Start reporting from a fresh Ledger.")(
390 "vacuum",
"VACUUM the transaction db.")(
391 "valid",
"Consider the initial ledger a valid network ledger.");
393 po::options_description rpc(
"RPC Client Options");
396 "Perform rpc command - see below for available commands. "
397 "This is assumed if any positional parameters are provided.")(
399 po::value<std::string>(),
400 "Specify the IP address for RPC command. "
401 "Format: <ip-address>[':'<port-number>]")(
403 po::value<std::uint16_t>(),
404 "DEPRECATED: include with rpc_ip instead. "
405 "Specify the port number for RPC command.");
407 po::options_description test(
"Unit Test Options");
410 "Suppress test suite messages, "
411 "including suite/case name (at start) and test log messages.")(
413 po::value<std::string>()->implicit_value(
""),
414 "Perform unit tests. The optional argument specifies one or "
415 "more comma-separated selectors. Each selector specifies a suite name, "
416 "full-name (lib.module.suite), module, or library "
420 po::value<std::string>()->implicit_value(
""),
421 "Supplies an argument string to unit tests. If provided, this argument "
422 "is made available to each suite that runs. Interpretation of the "
423 "argument is handled individually by any suite that accesses it -- "
424 "as such, it typically only make sense to provide this when running "
427 "Use IPv6 localhost when running unittests (default is IPv4).")(
429 "Force unit test log message output. Only useful in combination with "
430 "--quiet, in which case log messages will print but suite/case names "
433 po::value<std::size_t>(),
434 "Number of unittest jobs to run in parallel (child processes).");
438 po::options_description hidden(
"Hidden Options");
439 hidden.add_options()(
441 po::value<vector<string>>(),
442 "Specify rpc command and parameters. This option must be repeated "
443 "for each command/param. Positional parameters also serve this "
445 "so this option is not needed for users")(
447 "For internal use only when spawning child unit test processes.")(
448 "fg",
"Deprecated: server always in foreground mode.");
451 po::positional_options_description p;
452 p.add(
"parameters", -1);
454 po::options_description
all;
455 all.add(gen).add(rpc).add(data).add(test).add(hidden);
457 po::options_description desc;
458 desc.add(gen).add(rpc).add(data).add(test);
464 po::command_line_parser(argc, argv)
478 if (vm.count(
"help"))
484 if (vm.count(
"version"))
494 if (vm.count(
"unittest"))
498 if (vm.count(
"unittest-arg"))
502 bool unittestChild =
false;
503 if (vm.count(
"unittest-jobs"))
504 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
505 unittestChild = bool(vm.count(
"unittest-child"));
508 vm[
"unittest"].as<std::string>(),
510 bool(vm.count(
"quiet")),
511 bool(vm.count(
"unittest-log")),
513 bool(vm.count(
"unittest-ipv6")),
520 if (vm.count(
"unittest-jobs"))
523 std::cerr <<
"rippled: '--unittest-jobs' specified without "
525 std::cerr <<
"To run the unit tests the '--unittest' option must "
531 auto config = std::make_unique<Config>();
539 bool(vm.count(
"quiet")),
540 bool(vm.count(
"silent")),
541 bool(vm.count(
"standalone")));
543 if (vm.count(
"vacuum"))
545 if (config->standalone())
547 std::cerr <<
"vacuum not applicable in standalone mode.\n";
551 using namespace boost::filesystem;
553 path dbPath = dbSetup.dataDir /
TxDBName;
558 assert(dbSize !=
static_cast<uintmax_t>(-1));
560 if (
auto available =
space(dbPath.parent_path()).available;
563 std::cerr <<
"The database filesystem must have at least as "
564 "much free space as the size of "
565 << dbPath.string() <<
", which is " << dbSize
567 <<
" bytes are available.\n";
571 auto txnDB = std::make_unique<DatabaseCon>(
573 auto& session = txnDB->getSession();
580 session <<
"PRAGMA page_size;", soci::into(pageSize);
582 std::cout <<
"VACUUM beginning. page_size: " << pageSize
585 session <<
"VACUUM;";
586 assert(dbSetup.globalPragma);
587 for (
auto const& p : *dbSetup.globalPragma)
589 session <<
"PRAGMA page_size;", soci::into(pageSize);
591 std::cout <<
"VACUUM finished. page_size: " << pageSize
596 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
604 if (vm.count(
"start"))
609 if (vm.count(
"startReporting"))
612 config->START_LEDGER = vm[
"startReporting"].as<
std::string>();
615 if (vm.count(
"reportingReadOnly"))
617 config->setReportingReadOnly(
true);
620 if (vm.count(
"import"))
621 config->doImport =
true;
623 if (vm.count(
"nodetoshard"))
624 config->nodeToShard =
true;
626 if (vm.count(
"ledger"))
628 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
629 if (vm.count(
"replay"))
634 else if (vm.count(
"ledgerfile"))
636 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
639 else if (vm.count(
"load"))
644 if (vm.count(
"valid"))
646 config->START_VALID =
true;
654 std::cerr <<
"Net and load/replay options are incompatible"
664 if (vm.count(
"rpc_ip"))
667 vm[
"rpc_ip"].as<std::string>());
675 if (endpoint->port() == 0)
677 std::cerr <<
"No port specified in rpc_ip.\n";
678 if (vm.count(
"rpc_port"))
680 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
684 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
685 if (endpoint->port() == 0)
698 config->rpc_ip = std::move(*endpoint);
701 if (vm.count(
"quorum"))
705 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
713 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
723 if (vm.count(
"quiet"))
725 else if (vm.count(
"verbose"))
728 auto logs = std::make_unique<Logs>(thresh);
731 if (!vm.count(
"parameters"))
735 if (config->had_trailing_comments())
737 JLOG(logs->journal(
"Application").warn())
738 <<
"Trailing comments were seen in your config file. "
739 <<
"The treatment of inline/trailing comments has changed "
741 <<
"Any `#` characters NOT intended to delimit comments should "
743 <<
"preceded by a \\";
751 if (vm.count(
"debug"))
757 std::move(config), std::move(logs), std::move(timeKeeper));
765 app->fdRequired(), app->logs().journal(
"Application")))
788 main(
int argc,
char** argv)
808 atexit(&google::protobuf::ShutdownProtobufLibrary);
810 auto const result(ripple::run(argc, argv));