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).";
358 shardsText +=
"Validate an existing shard database (specified in the [";
360 shardsText +=
"] configuration file section).";
365 po::options_description gen(
"General Options");
367 "conf", po::value<std::string>(),
"Specify the configuration file.")(
368 "debug",
"Enable normally suppressed debug logging")(
369 "help,h",
"Display this message.")(
371 po::value<std::size_t>(),
372 "Override the minimum validation quorum.")(
373 "silent",
"No output to the console after startup.")(
374 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
375 "version",
"Display the build version.");
377 po::options_description
data(
"Ledger/Data Options");
378 data.add_options()(
"import", importText.
c_str())(
380 po::value<std::string>(),
381 "Load the specified ledger and start from the value given.")(
383 po::value<std::string>(),
384 "Load the specified ledger file.")(
385 "load",
"Load the current ledger from the local DB.")(
386 "net",
"Get the initial ledger from the network.")(
387 "nodetoshard",
"Import node store into shards")(
388 "replay",
"Replay a ledger close.")(
389 "start",
"Start from a fresh Ledger.")(
390 "vacuum",
"VACUUM the transaction db.")(
391 "valid",
"Consider the initial ledger a valid network ledger.")(
392 "validateShards", shardsText.
c_str());
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";
552 using namespace boost::filesystem;
554 path dbPath = dbSetup.dataDir /
TxDBName;
559 assert(dbSize !=
static_cast<uintmax_t>(-1));
561 if (
auto available =
space(dbPath.parent_path()).available;
564 std::cerr <<
"The database filesystem must have at least as "
565 "much free space as the size of "
566 << dbPath.string() <<
", which is " << dbSize
567 <<
" bytes. Only " << available
568 <<
" bytes are available.\n";
572 auto txnDB = std::make_unique<DatabaseCon>(
574 auto& session = txnDB->getSession();
581 session <<
"PRAGMA page_size;", soci::into(pageSize);
583 std::cout <<
"VACUUM beginning. page_size: " << pageSize
586 session <<
"VACUUM;";
587 assert(dbSetup.globalPragma);
588 for (
auto const& p : *dbSetup.globalPragma)
590 session <<
"PRAGMA page_size;", soci::into(pageSize);
592 std::cout <<
"VACUUM finished. page_size: " << pageSize
597 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
605 if (vm.count(
"start"))
608 if (vm.count(
"import"))
609 config->doImport =
true;
611 if (vm.count(
"nodetoshard"))
612 config->nodeToShard =
true;
614 if (vm.count(
"validateShards"))
615 config->validateShards =
true;
617 if (vm.count(
"ledger"))
619 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
620 if (vm.count(
"replay"))
625 else if (vm.count(
"ledgerfile"))
627 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
630 else if (vm.count(
"load"))
635 if (vm.count(
"valid"))
637 config->START_VALID =
true;
645 std::cerr <<
"Net and load/replay options are incompatible"
655 if (vm.count(
"rpc_ip"))
658 vm[
"rpc_ip"].as<std::string>());
666 if (endpoint->port() == 0)
668 std::cerr <<
"No port specified in rpc_ip.\n";
669 if (vm.count(
"rpc_port"))
671 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
675 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
676 if (endpoint->port() == 0)
689 config->rpc_ip = std::move(*endpoint);
692 if (vm.count(
"quorum"))
696 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
704 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
714 if (vm.count(
"quiet"))
716 else if (vm.count(
"verbose"))
719 auto logs = std::make_unique<Logs>(thresh);
722 if (!vm.count(
"parameters"))
726 if (config->had_trailing_comments())
728 JLOG(logs->journal(
"Application").warn())
729 <<
"Trailing comments were seen in your config file. "
730 <<
"The treatment of inline/trailing comments has changed "
732 <<
"Any `#` characters NOT intended to delimit comments should "
734 <<
"preceded by a \\";
742 if (vm.count(
"debug"))
748 std::move(config), std::move(logs), std::move(timeKeeper));
756 app->fdRequired(), app->logs().journal(
"Application")))
779 main(
int argc,
char** argv)
799 atexit(&google::protobuf::ShutdownProtobufLibrary);
801 auto const result(ripple::run(argc, argv));