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)
89 available = rl.rlim_cur;
91 if (available < needed)
98 if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
99 available = rl.rlim_cur;
103 if (needed > available)
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
109 <<
" are needed, but only " << available
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 "silent",
"No output to the console after startup.")(
370 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
371 "version",
"Display the build version.");
373 po::options_description
data(
"Ledger/Data Options");
374 data.add_options()(
"import", importText.
c_str())(
376 po::value<std::string>(),
377 "Load the specified ledger and start from the value given.")(
379 po::value<std::string>(),
380 "Load the specified ledger file.")(
381 "load",
"Load the current ledger from the local DB.")(
382 "net",
"Get the initial ledger from the network.")(
383 "nodetoshard",
"Import node store into shards")(
384 "replay",
"Replay a ledger close.")(
385 "start",
"Start from a fresh Ledger.")(
386 "vacuum",
"VACUUM the transaction db.")(
387 "valid",
"Consider the initial ledger a valid network ledger.");
389 po::options_description rpc(
"RPC Client Options");
392 "Perform rpc command - see below for available commands. "
393 "This is assumed if any positional parameters are provided.")(
395 po::value<std::string>(),
396 "Specify the IP address for RPC command. "
397 "Format: <ip-address>[':'<port-number>]")(
399 po::value<std::uint16_t>(),
400 "DEPRECATED: include with rpc_ip instead. "
401 "Specify the port number for RPC command.");
403 po::options_description test(
"Unit Test Options");
406 "Suppress test suite messages, "
407 "including suite/case name (at start) and test log messages.")(
409 po::value<std::string>()->implicit_value(
""),
410 "Perform unit tests. The optional argument specifies one or "
411 "more comma-separated selectors. Each selector specifies a suite name, "
412 "full-name (lib.module.suite), module, or library "
416 po::value<std::string>()->implicit_value(
""),
417 "Supplies an argument string to unit tests. If provided, this argument "
418 "is made available to each suite that runs. Interpretation of the "
419 "argument is handled individually by any suite that accesses it -- "
420 "as such, it typically only make sense to provide this when running "
423 "Use IPv6 localhost when running unittests (default is IPv4).")(
425 "Force unit test log message output. Only useful in combination with "
426 "--quiet, in which case log messages will print but suite/case names "
429 po::value<std::size_t>(),
430 "Number of unittest jobs to run in parallel (child processes).");
434 po::options_description hidden(
"Hidden Options");
435 hidden.add_options()(
437 po::value<vector<string>>(),
438 "Specify rpc command and parameters. This option must be repeated "
439 "for each command/param. Positional parameters also serve this "
441 "so this option is not needed for users")(
443 "For internal use only when spawning child unit test processes.")(
444 "fg",
"Deprecated: server always in foreground mode.");
447 po::positional_options_description p;
448 p.add(
"parameters", -1);
450 po::options_description
all;
451 all.add(gen).add(rpc).add(data).add(test).add(hidden);
453 po::options_description desc;
454 desc.add(gen).add(rpc).add(data).add(test);
460 po::command_line_parser(argc, argv)
474 if (vm.count(
"help"))
480 if (vm.count(
"version"))
490 if (vm.count(
"unittest"))
494 if (vm.count(
"unittest-arg"))
498 bool unittestChild =
false;
499 if (vm.count(
"unittest-jobs"))
500 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
501 unittestChild = bool(vm.count(
"unittest-child"));
504 vm[
"unittest"].as<std::string>(),
506 bool(vm.count(
"quiet")),
507 bool(vm.count(
"unittest-log")),
509 bool(vm.count(
"unittest-ipv6")),
516 if (vm.count(
"unittest-jobs"))
519 std::cerr <<
"rippled: '--unittest-jobs' specified without "
521 std::cerr <<
"To run the unit tests the '--unittest' option must "
527 auto config = std::make_unique<Config>();
535 bool(vm.count(
"quiet")),
536 bool(vm.count(
"silent")),
537 bool(vm.count(
"standalone")));
539 if (vm.count(
"vacuum"))
541 if (config->standalone())
543 std::cerr <<
"vacuum not applicable in standalone mode.\n";
547 using namespace boost::filesystem;
549 path dbPath = dbSetup.dataDir /
TxDBName;
554 assert(dbSize !=
static_cast<uintmax_t>(-1));
556 if (
auto available =
space(dbPath.parent_path()).available;
559 std::cerr <<
"The database filesystem must have at least as "
560 "much free space as the size of "
561 << dbPath.string() <<
", which is " << dbSize
562 <<
" bytes. Only " << available
563 <<
" bytes are available.\n";
567 auto txnDB = std::make_unique<DatabaseCon>(
569 auto& session = txnDB->getSession();
576 session <<
"PRAGMA page_size;", soci::into(pageSize);
578 std::cout <<
"VACUUM beginning. page_size: " << pageSize
581 session <<
"VACUUM;";
582 assert(dbSetup.globalPragma);
583 for (
auto const& p : *dbSetup.globalPragma)
585 session <<
"PRAGMA page_size;", soci::into(pageSize);
587 std::cout <<
"VACUUM finished. page_size: " << pageSize
592 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
600 if (vm.count(
"start"))
603 if (vm.count(
"import"))
604 config->doImport =
true;
606 if (vm.count(
"nodetoshard"))
607 config->nodeToShard =
true;
609 if (vm.count(
"ledger"))
611 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
612 if (vm.count(
"replay"))
617 else if (vm.count(
"ledgerfile"))
619 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
622 else if (vm.count(
"load"))
627 if (vm.count(
"valid"))
629 config->START_VALID =
true;
637 std::cerr <<
"Net and load/replay options are incompatible"
647 if (vm.count(
"rpc_ip"))
650 vm[
"rpc_ip"].as<std::string>());
658 if (endpoint->port() == 0)
660 std::cerr <<
"No port specified in rpc_ip.\n";
661 if (vm.count(
"rpc_port"))
663 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
667 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
668 if (endpoint->port() == 0)
681 config->rpc_ip = std::move(*endpoint);
684 if (vm.count(
"quorum"))
688 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
696 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
706 if (vm.count(
"quiet"))
708 else if (vm.count(
"verbose"))
711 auto logs = std::make_unique<Logs>(thresh);
714 if (!vm.count(
"parameters"))
718 if (config->had_trailing_comments())
720 JLOG(logs->journal(
"Application").warn())
721 <<
"Trailing comments were seen in your config file. "
722 <<
"The treatment of inline/trailing comments has changed "
724 <<
"Any `#` characters NOT intended to delimit comments should "
726 <<
"preceded by a \\";
734 if (vm.count(
"debug"))
740 std::move(config), std::move(logs), std::move(timeKeeper));
748 app->fdRequired(), app->logs().journal(
"Application")))
771 main(
int argc,
char** argv)
791 atexit(&google::protobuf::ShutdownProtobufLibrary);
793 auto const result(ripple::run(argc, argv));