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_)
239 if (!child && num_jobs == 1)
244 child_runner.arg(argument);
245 auto const any_failed = child_runner.run_multi(multi_selector(pattern));
260 for (
int i = 1; i < argc; ++i)
267 boost::process::exe = exe_name, boost::process::args = args);
269 int bad_child_exits = 0;
270 for (
auto& c : children)
285 if (parent_runner.
any_failed() || bad_child_exits)
293 runner.arg(argument);
294 auto const anyFailed = runner.run_multi(multi_selector(pattern));
305 run(
int argc,
char** argv)
312 po::variables_map vm;
316 importText +=
"Import an existing node database (specified in the [";
318 importText +=
"] configuration file section) into the current ";
319 importText +=
"node database (specified in the [";
321 importText +=
"] configuration file section).";
325 shardsText +=
"Validate an existing shard database (specified in the [";
327 shardsText +=
"] configuration file section).";
332 po::options_description gen(
"General Options");
334 "conf", po::value<std::string>(),
"Specify the configuration file.")(
335 "debug",
"Enable normally suppressed debug logging")(
336 "help,h",
"Display this message.")(
338 po::value<std::size_t>(),
339 "Override the minimum validation quorum.")(
340 "silent",
"No output to the console after startup.")(
341 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")(
342 "version",
"Display the build version.");
344 po::options_description
data(
"Ledger/Data Options");
345 data.add_options()(
"import", importText.
c_str())(
347 po::value<std::string>(),
348 "Load the specified ledger and start from the value given.")(
350 po::value<std::string>(),
351 "Load the specified ledger file.")(
352 "load",
"Load the current ledger from the local DB.")(
353 "net",
"Get the initial ledger from the network.")(
354 "nodetoshard",
"Import node store into shards")(
355 "replay",
"Replay a ledger close.")(
356 "start",
"Start from a fresh Ledger.")(
358 po::value<std::string>(),
359 "VACUUM the transaction db. Mandatory string argument specifies "
360 "temporary directory path.")(
361 "valid",
"Consider the initial ledger a valid network ledger.")(
362 "validateShards", shardsText.
c_str());
364 po::options_description rpc(
"RPC Client Options");
367 "Perform rpc command - see below for available commands. "
368 "This is assumed if any positional parameters are provided.")(
370 po::value<std::string>(),
371 "Specify the IP address for RPC command. "
372 "Format: <ip-address>[':'<port-number>]")(
374 po::value<std::uint16_t>(),
375 "DEPRECATED: include with rpc_ip instead. "
376 "Specify the port number for RPC command.");
378 po::options_description test(
"Unit Test Options");
381 "Suppress test suite messages, "
382 "including suite/case name (at start) and test log messages.")(
384 po::value<std::string>()->implicit_value(
""),
385 "Perform unit tests. The optional argument specifies one or "
386 "more comma-separated selectors. Each selector specifies a suite name, "
387 "full-name (lib.module.suite), module, or library "
391 po::value<std::string>()->implicit_value(
""),
392 "Supplies an argument string to unit tests. If provided, this argument "
393 "is made available to each suite that runs. Interpretation of the "
394 "argument is handled individually by any suite that accesses it -- "
395 "as such, it typically only make sense to provide this when running "
398 "Use IPv6 localhost when running unittests (default is IPv4).")(
400 "Force unit test log message output. Only useful in combination with "
401 "--quiet, in which case log messages will print but suite/case names "
404 po::value<std::size_t>(),
405 "Number of unittest jobs to run in parallel (child processes).");
409 po::options_description hidden(
"Hidden Options");
410 hidden.add_options()(
412 po::value<vector<string>>(),
413 "Specify rpc command and parameters. This option must be repeated "
414 "for each command/param. Positional parameters also serve this "
416 "so this option is not needed for users")(
418 "For internal use only when spawning child unit test processes.")(
419 "fg",
"Deprecated: server always in foreground mode.");
422 po::positional_options_description p;
423 p.add(
"parameters", -1);
425 po::options_description all;
426 all.add(gen).add(rpc).add(data).add(test).add(hidden);
428 po::options_description desc;
429 desc.add(gen).add(rpc).add(data).add(test);
435 po::command_line_parser(argc, argv)
449 if (vm.count(
"help"))
455 if (vm.count(
"version"))
465 if (vm.count(
"unittest"))
469 if (vm.count(
"unittest-arg"))
473 bool unittestChild =
false;
474 if (vm.count(
"unittest-jobs"))
475 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
476 unittestChild = bool(vm.count(
"unittest-child"));
479 vm[
"unittest"].as<std::string>(),
481 bool(vm.count(
"quiet")),
482 bool(vm.count(
"unittest-log")),
484 bool(vm.count(
"unittest-ipv6")),
491 if (vm.count(
"unittest-jobs"))
494 std::cerr <<
"rippled: '--unittest-jobs' specified without "
496 std::cerr <<
"To run the unit tests the '--unittest' option must "
502 auto config = std::make_unique<Config>();
510 bool(vm.count(
"quiet")),
511 bool(vm.count(
"silent")),
512 bool(vm.count(
"standalone")));
514 if (vm.count(
"vacuum"))
516 if (config->standalone())
518 std::cerr <<
"vacuum not applicable in standalone mode.\n";
522 using namespace boost::filesystem;
524 path dbPath = dbSetup.dataDir /
TxDBName;
530 assert(dbSize !=
static_cast<uintmax_t>(-1));
532 if (
space(tmpPath).available < dbSize)
534 std::cerr <<
"A valid directory for vacuuming must be "
535 "specified on a filesystem with at least "
536 "as much free space as the size of "
537 << dbPath.string() <<
", which is " << dbSize
538 <<
" bytes. The filesystem for " << tmpPath.string()
539 <<
" only has " <<
space(tmpPath).available
544 auto txnDB = std::make_unique<DatabaseCon>(
546 auto& session = txnDB->getSession();
549 session <<
"PRAGMA page_size;", soci::into(pageSize);
551 std::cout <<
"VACUUM beginning. page_size: " << pageSize
554 session <<
"PRAGMA journal_mode=OFF;";
555 session <<
"PRAGMA temp_store_directory=\"" << tmpPath.string()
557 session <<
"VACUUM;";
558 session <<
"PRAGMA journal_mode=WAL;";
559 session <<
"PRAGMA page_size;", soci::into(pageSize);
561 std::cout <<
"VACUUM finished. page_size: " << pageSize
566 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
574 if (vm.count(
"start"))
577 if (vm.count(
"import"))
578 config->doImport =
true;
580 if (vm.count(
"nodetoshard"))
581 config->nodeToShard =
true;
583 if (vm.count(
"validateShards"))
584 config->validateShards =
true;
586 if (vm.count(
"ledger"))
588 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
589 if (vm.count(
"replay"))
594 else if (vm.count(
"ledgerfile"))
596 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
599 else if (vm.count(
"load"))
604 if (vm.count(
"valid"))
606 config->START_VALID =
true;
614 std::cerr <<
"Net and load/reply options are incompatible"
624 if (vm.count(
"rpc_ip"))
627 vm[
"rpc_ip"].as<std::string>());
635 if (endpoint->port() == 0)
637 std::cerr <<
"No port specified in rpc_ip.\n";
638 if (vm.count(
"rpc_port"))
640 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
644 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
645 if (endpoint->port() == 0)
658 config->rpc_ip = std::move(*endpoint);
661 if (vm.count(
"quorum"))
665 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
673 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
683 if (vm.count(
"quiet"))
685 else if (vm.count(
"verbose"))
688 auto logs = std::make_unique<Logs>(thresh);
691 if (!vm.count(
"parameters"))
695 if (config->had_trailing_comments())
697 JLOG(logs->journal(
"Application").warn())
698 <<
"Trailing comments were seen in your config file. "
699 <<
"The treatment of inline/trailing comments has changed "
701 <<
"Any `#` characters NOT intended to delimit comments should "
703 <<
"preceded by a \\";
711 if (vm.count(
"debug"))
717 std::move(config), std::move(logs), std::move(timeKeeper));
725 app->fdRequired(), app->logs().journal(
"Application")))
748 main(
int argc,
char** argv)
768 atexit(&google::protobuf::ShutdownProtobufLibrary);
770 auto const result(ripple::run(argc, argv));