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 for (
auto& c : children)
316 anyMissing(parent_runner, multi_selector(pattern));
318 if (parent_runner.
any_failed() || bad_child_exits)
326 runner.arg(argument);
327 auto const anyFailed = runner.run_multi(multi_selector(pattern));
338 run(
int argc,
char** argv)
345 po::variables_map vm;
349 importText +=
"Import an existing node database (specified in the [";
351 importText +=
"] configuration file section) into the current ";
352 importText +=
"node database (specified in the [";
354 importText +=
"] configuration file section).";
359 po::options_description gen(
"General Options");
361 "conf", po::value<std::string>(),
"Specify the configuration file.")(
362 "debug",
"Enable normally suppressed debug logging")(
363 "help,h",
"Display this message.")(
365 po::value<std::size_t>(),
366 "Override the minimum validation quorum.")(
367 "silent",
"No output to the console after startup.")(
368 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
369 "version",
"Display the build version.");
371 po::options_description
data(
"Ledger/Data Options");
372 data.add_options()(
"import", importText.
c_str())(
374 po::value<std::string>(),
375 "Load the specified ledger and start from the value given.")(
377 po::value<std::string>(),
378 "Load the specified ledger file.")(
379 "load",
"Load the current ledger from the local DB.")(
380 "net",
"Get the initial ledger from the network.")(
381 "nodetoshard",
"Import node store into shards")(
382 "replay",
"Replay a ledger close.")(
383 "start",
"Start from a fresh Ledger.")(
384 "vacuum",
"VACUUM the transaction db.")(
385 "valid",
"Consider the initial ledger a valid network ledger.");
387 po::options_description rpc(
"RPC Client Options");
390 "Perform rpc command - see below for available commands. "
391 "This is assumed if any positional parameters are provided.")(
393 po::value<std::string>(),
394 "Specify the IP address for RPC command. "
395 "Format: <ip-address>[':'<port-number>]")(
397 po::value<std::uint16_t>(),
398 "DEPRECATED: include with rpc_ip instead. "
399 "Specify the port number for RPC command.");
401 po::options_description test(
"Unit Test Options");
404 "Suppress test suite messages, "
405 "including suite/case name (at start) and test log messages.")(
407 po::value<std::string>()->implicit_value(
""),
408 "Perform unit tests. The optional argument specifies one or "
409 "more comma-separated selectors. Each selector specifies a suite name, "
410 "full-name (lib.module.suite), module, or library "
414 po::value<std::string>()->implicit_value(
""),
415 "Supplies an argument string to unit tests. If provided, this argument "
416 "is made available to each suite that runs. Interpretation of the "
417 "argument is handled individually by any suite that accesses it -- "
418 "as such, it typically only make sense to provide this when running "
421 "Use IPv6 localhost when running unittests (default is IPv4).")(
423 "Force unit test log message output. Only useful in combination with "
424 "--quiet, in which case log messages will print but suite/case names "
427 po::value<std::size_t>(),
428 "Number of unittest jobs to run in parallel (child processes).");
432 po::options_description hidden(
"Hidden Options");
433 hidden.add_options()(
435 po::value<vector<string>>(),
436 "Specify rpc command and parameters. This option must be repeated "
437 "for each command/param. Positional parameters also serve this "
439 "so this option is not needed for users")(
441 "For internal use only when spawning child unit test processes.")(
442 "fg",
"Deprecated: server always in foreground mode.");
445 po::positional_options_description p;
446 p.add(
"parameters", -1);
448 po::options_description
all;
449 all.add(gen).add(rpc).add(data).add(test).add(hidden);
451 po::options_description desc;
452 desc.add(gen).add(rpc).add(data).add(test);
458 po::command_line_parser(argc, argv)
472 if (vm.count(
"help"))
478 if (vm.count(
"version"))
488 if (vm.count(
"unittest"))
492 if (vm.count(
"unittest-arg"))
496 bool unittestChild =
false;
497 if (vm.count(
"unittest-jobs"))
498 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
499 unittestChild = bool(vm.count(
"unittest-child"));
502 vm[
"unittest"].as<std::string>(),
504 bool(vm.count(
"quiet")),
505 bool(vm.count(
"unittest-log")),
507 bool(vm.count(
"unittest-ipv6")),
514 if (vm.count(
"unittest-jobs"))
517 std::cerr <<
"rippled: '--unittest-jobs' specified without "
519 std::cerr <<
"To run the unit tests the '--unittest' option must "
525 auto config = std::make_unique<Config>();
533 bool(vm.count(
"quiet")),
534 bool(vm.count(
"silent")),
535 bool(vm.count(
"standalone")));
537 if (vm.count(
"vacuum"))
539 if (config->standalone())
541 std::cerr <<
"vacuum not applicable in standalone mode.\n";
545 using namespace boost::filesystem;
547 path dbPath = dbSetup.dataDir /
TxDBName;
552 assert(dbSize !=
static_cast<uintmax_t>(-1));
554 if (
auto available =
space(dbPath.parent_path()).available;
557 std::cerr <<
"The database filesystem must have at least as "
558 "much free space as the size of "
559 << dbPath.string() <<
", which is " << dbSize
560 <<
" bytes. Only " << available
561 <<
" bytes are available.\n";
565 auto txnDB = std::make_unique<DatabaseCon>(
567 auto& session = txnDB->getSession();
574 session <<
"PRAGMA page_size;", soci::into(pageSize);
576 std::cout <<
"VACUUM beginning. page_size: " << pageSize
579 session <<
"VACUUM;";
580 assert(dbSetup.globalPragma);
581 for (
auto const& p : *dbSetup.globalPragma)
583 session <<
"PRAGMA page_size;", soci::into(pageSize);
585 std::cout <<
"VACUUM finished. page_size: " << pageSize
590 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
598 if (vm.count(
"start"))
601 if (vm.count(
"import"))
602 config->doImport =
true;
604 if (vm.count(
"nodetoshard"))
605 config->nodeToShard =
true;
607 if (vm.count(
"ledger"))
609 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
610 if (vm.count(
"replay"))
615 else if (vm.count(
"ledgerfile"))
617 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
620 else if (vm.count(
"load"))
625 if (vm.count(
"valid"))
627 config->START_VALID =
true;
635 std::cerr <<
"Net and load/replay options are incompatible"
645 if (vm.count(
"rpc_ip"))
648 vm[
"rpc_ip"].as<std::string>());
656 if (endpoint->port() == 0)
658 std::cerr <<
"No port specified in rpc_ip.\n";
659 if (vm.count(
"rpc_port"))
661 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
665 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
666 if (endpoint->port() == 0)
679 config->rpc_ip = std::move(*endpoint);
682 if (vm.count(
"quorum"))
686 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
694 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
704 if (vm.count(
"quiet"))
706 else if (vm.count(
"verbose"))
709 auto logs = std::make_unique<Logs>(thresh);
712 if (!vm.count(
"parameters"))
716 if (config->had_trailing_comments())
718 JLOG(logs->journal(
"Application").warn())
719 <<
"Trailing comments were seen in your config file. "
720 <<
"The treatment of inline/trailing comments has changed "
722 <<
"Any `#` characters NOT intended to delimit comments should "
724 <<
"preceded by a \\";
732 if (vm.count(
"debug"))
738 std::move(config), std::move(logs), std::move(timeKeeper));
746 app->fdRequired(), app->logs().journal(
"Application")))
769 main(
int argc,
char** argv)
789 atexit(&google::protobuf::ShutdownProtobufLibrary);
791 auto const result(ripple::run(argc, argv));