21 #include <ripple/basics/Log.h>
22 #include <ripple/protocol/digest.h>
23 #include <ripple/app/main/Application.h>
24 #include <ripple/app/main/DBInit.h>
25 #include <ripple/basics/contract.h>
26 #include <ripple/basics/StringUtilities.h>
27 #include <ripple/basics/Sustain.h>
28 #include <ripple/core/Config.h>
29 #include <ripple/core/ConfigSections.h>
30 #include <ripple/core/DatabaseCon.h>
31 #include <ripple/core/TimeKeeper.h>
32 #include <ripple/json/to_string.h>
33 #include <ripple/net/RPCCall.h>
34 #include <ripple/resource/Fees.h>
35 #include <ripple/rpc/RPCHandler.h>
36 #include <ripple/protocol/BuildInfo.h>
37 #include <ripple/beast/clock/basic_seconds_clock.h>
38 #include <ripple/beast/core/CurrentThreadName.h>
40 #include <beast/unit_test/match.hpp>
41 #include <test/unit_test/multi_runner.h>
43 #include <google/protobuf/stubs/common.h>
45 #include <boost/filesystem.hpp>
46 #include <boost/process.hpp>
47 #include <boost/program_options.hpp>
48 #include <boost/predef.h>
56 #include <sys/types.h>
57 #include <sys/timeb.h>
62 #if !BOOST_OS_LINUX && !BOOST_OS_WINDOWS && !BOOST_OS_MACOS
63 #error Supported platforms are: Linux, Windows and MacOS
67 #if (BOOST_OS_LINUX && (BOOST_OS_WINDOWS || BOOST_OS_MACOS)) || \
68 (BOOST_OS_MACOS && (BOOST_OS_WINDOWS || BOOST_OS_LINUX)) || \
69 (BOOST_OS_WINDOWS && (BOOST_OS_LINUX || BOOST_OS_MACOS))
70 #error Multiple supported platforms appear active at once
73 namespace po = boost::program_options;
86 if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
89 if (rl.rlim_cur == RLIM_INFINITY)
92 available = rl.rlim_cur;
94 if (available < needed)
101 if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
102 available = rl.rlim_cur;
106 if (needed > available)
109 "Insufficient number of file descriptors: " <<
110 needed <<
" are needed, but only " <<
111 available <<
" are available.";
114 "Insufficient number of file descriptors: " <<
115 needed <<
" are needed, but only " <<
116 available <<
" are available.\n";
128 <<
systemName () <<
"d [options] <command> <params>\n"
131 " account_currencies <account> [<ledger>] [strict]\n"
132 " account_info <account>|<seed>|<pass_phrase>|<key> [<ledger>] [strict]\n"
133 " account_lines <account> <account>|\"\" [<ledger>]\n"
134 " account_channels <account> <account>|\"\" [<ledger>]\n"
135 " account_objects <account> [<ledger>] [strict]\n"
136 " account_offers <account>|<account_public_key> [<ledger>] [strict]\n"
137 " account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] [count] [descending]\n"
138 " book_offers <taker_pays> <taker_gets> [<taker [<ledger> [<limit> [<proof> [<marker>]]]]]\n"
139 " can_delete [<ledgerid>|<ledgerhash>|now|always|never]\n"
140 " channel_authorize <private_key> <channel_id> <drops>\n"
141 " channel_verify <public_key> <channel_id> <drops> <signature>\n"
142 " connect <ip> [<port>]\n"
144 " deposit_authorized <source_account> <destination_account> [<ledger>]\n"
145 " download_shard [[<index> <url>]]\n"
146 " feature [<feature> [accept|reject]]\n"
147 " fetch_info [clear]\n"
148 " gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ <hotwallet> ]]\n"
150 " json <method> <json>\n"
151 " ledger [<id>|current|closed|validated] [full]\n"
156 " ledger_request <ledger>\n"
157 " log_level [[<partition>] <severity>]\n"
162 " peer_reservations_add <public_key> [<description>]\n"
163 " peer_reservations_del <public_key>\n"
164 " peer_reservations_list\n"
166 " ripple_path_find <json> [<ledger>]\n"
167 " server_info [counters]\n"
168 " server_state [counters]\n"
169 " sign <private_key> <tx_json> [offline]\n"
170 " sign_for <signer_address> <signer_private_key> <tx_json> [offline]\n"
172 " submit <tx_blob>|[<private_key> <tx_json>]\n"
173 " submit_multisigned <tx_json>\n"
175 " validation_create [<seed>|<pass_phrase>|<key>]\n"
177 " validator_list_sites\n"
179 " wallet_propose [<passphrase>]\n";
196 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 static int runUnitTests(
236 if (!child && num_jobs == 1)
241 child_runner.arg(argument);
242 auto const any_failed = child_runner.run_multi(multi_selector(pattern));
257 for (
int i = 1; i < argc; ++i)
264 boost::process::exe = exe_name, boost::process::args = args);
266 int bad_child_exits = 0;
267 for(
auto& c : children)
282 if (parent_runner.
any_failed() || bad_child_exits)
290 runner.arg(argument);
291 auto const anyFailed = runner.run_multi(multi_selector(pattern));
301 int run (
int argc,
char** argv)
307 po::variables_map vm;
311 importText +=
"Import an existing node database (specified in the [";
313 importText +=
"] configuration file section) into the current ";
314 importText +=
"node database (specified in the [";
316 importText +=
"] configuration file section).";
320 shardsText +=
"Validate an existing shard database (specified in the [";
322 shardsText +=
"] configuration file section).";
327 po::options_description gen (
"General Options");
329 (
"conf", po::value<std::string> (),
"Specify the configuration file.")
330 (
"debug",
"Enable normally suppressed debug logging")
331 (
"fg",
"Run in the foreground.")
332 (
"help,h",
"Display this message.")
333 (
"quorum", po::value <std::size_t> (),
334 "Override the minimum validation quorum.")
335 (
"silent",
"No output to the console after startup.")
336 (
"standalone,a",
"Run with no peers.")
337 (
"verbose,v",
"Verbose logging.")
338 (
"version",
"Display the build version.")
341 po::options_description
data (
"Ledger/Data Options");
343 (
"import", importText.
c_str ())
344 (
"ledger", po::value<std::string> (),
345 "Load the specified ledger and start from the value given.")
346 (
"ledgerfile", po::value<std::string> (),
"Load the specified ledger file.")
347 (
"load",
"Load the current ledger from the local DB.")
348 (
"net",
"Get the initial ledger from the network.")
349 (
"nodetoshard",
"Import node store into shards")
350 (
"replay",
"Replay a ledger close.")
351 (
"start",
"Start from a fresh Ledger.")
352 (
"vacuum", po::value<std::string>(),
353 "VACUUM the transaction db. Mandatory string argument specifies "
354 "temporary directory path.")
355 (
"valid",
"Consider the initial ledger a valid network ledger.")
356 (
"validateShards", shardsText.
c_str ())
359 po::options_description rpc (
"RPC Client Options");
362 "Perform rpc command - see below for available commands. "
363 "This is assumed if any positional parameters are provided.")
364 (
"rpc_ip", po::value <std::string> (),
365 "Specify the IP address for RPC command. "
366 "Format: <ip-address>[':'<port-number>]")
367 (
"rpc_port", po::value <std::uint16_t> (),
368 "DEPRECATED: include with rpc_ip instead. "
369 "Specify the port number for RPC command.")
372 po::options_description test (
"Unit Test Options");
375 "Suppress test suite messages, "
376 "including suite/case name (at start) and test log messages.")
377 (
"unittest,u", po::value <std::string> ()->implicit_value (
""),
378 "Perform unit tests. The optional argument specifies one or "
379 "more comma-separated selectors. Each selector specifies a suite name, "
380 "full-name (lib.module.suite), module, or library "
381 "(checked in that ""order).")
382 (
"unittest-arg", po::value <std::string> ()->implicit_value (
""),
383 "Supplies an argument string to unit tests. If provided, this argument "
384 "is made available to each suite that runs. Interpretation of the "
385 "argument is handled individually by any suite that accesses it -- "
386 "as such, it typically only make sense to provide this when running "
388 (
"unittest-ipv6",
"Use IPv6 localhost when running unittests (default is IPv4).")
390 "Force unit test log message output. Only useful in combination with "
391 "--quiet, in which case log messages will print but suite/case names "
393 (
"unittest-jobs", po::value <std::size_t> (),
394 "Number of unittest jobs to run in parallel (child processes).")
398 po::options_description hidden (
"Hidden Options");
400 (
"parameters", po::value< vector<string> > (),
401 "Specify rpc command and parameters. This option must be repeated "
402 "for each command/param. Positional parameters also serve this purpose, "
403 "so this option is not needed for users")
405 "For internal use only when spawning child unit test processes.")
409 po::positional_options_description p;
410 p.add (
"parameters", -1);
412 po::options_description all;
413 all.add(gen).add(rpc).add(data).add(test).add(hidden);
415 po::options_description desc;
416 desc.add(gen).add(rpc).add(data).add(test);
421 po::store (po::command_line_parser (argc, argv)
435 if (vm.count (
"help"))
441 if (vm.count (
"version"))
451 if (vm.count (
"unittest"))
455 if (vm.count(
"unittest-arg"))
459 bool unittestChild =
false;
460 if (vm.count(
"unittest-jobs"))
461 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
462 unittestChild = bool (vm.count(
"unittest-child"));
465 vm[
"unittest"].as<std::string>(), argument,
466 bool (vm.count (
"quiet")),
467 bool (vm.count (
"unittest-log")),
469 bool (vm.count (
"unittest-ipv6")),
476 if (vm.count(
"unittest-jobs"))
479 std::cerr <<
"rippled: '--unittest-jobs' specified without '--unittest'.\n";
480 std::cerr <<
"To run the unit tests the '--unittest' option must be present.\n";
485 auto config = std::make_unique<Config>();
487 auto configFile = vm.count (
"conf") ?
491 config->setup (configFile,
bool (vm.count (
"quiet")),
492 bool(vm.count(
"silent")),
bool(vm.count(
"standalone")));
494 if (vm.count(
"vacuum"))
496 if (config->standalone())
498 std::cerr <<
"vacuum not applicable in standalone mode.\n";
502 using namespace boost::filesystem;
504 path dbPath = dbSetup.dataDir /
TxDBName;
510 assert(dbSize !=
static_cast<uintmax_t>(-1));
512 if (
space(tmpPath).available < dbSize)
514 std::cerr <<
"A valid directory for vacuuming must be "
515 "specified on a filesystem with at least "
516 "as much free space as the size of "
517 << dbPath.string() <<
", which is " << dbSize
518 <<
" bytes. The filesystem for " << tmpPath.string()
520 <<
space(tmpPath).available
525 auto txnDB = std::make_unique<DatabaseCon>(
527 auto& session = txnDB->getSession();
530 session <<
"PRAGMA page_size;", soci::into(pageSize);
532 std::cout <<
"VACUUM beginning. page_size: " <<
535 session <<
"PRAGMA journal_mode=OFF;";
536 session <<
"PRAGMA temp_store_directory=\"" <<
537 tmpPath.string() <<
"\";";
538 session <<
"VACUUM;";
539 session <<
"PRAGMA journal_mode=WAL;";
540 session <<
"PRAGMA page_size;", soci::into(pageSize);
542 std::cout <<
"VACUUM finished. page_size: " <<
548 " in function " << __func__ <<
std::endl;
555 if (vm.count (
"start"))
558 if (vm.count (
"import"))
559 config->doImport =
true;
561 if (vm.count(
"nodetoshard"))
562 config->nodeToShard =
true;
564 if (vm.count (
"validateShards"))
565 config->validateShards =
true;
567 if (vm.count (
"ledger"))
569 config->START_LEDGER = vm[
"ledger"].as<
std::string> ();
570 if (vm.count(
"replay"))
575 else if (vm.count (
"ledgerfile"))
577 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string> ();
580 else if (vm.count (
"load"))
585 if (vm.count (
"valid"))
587 config->START_VALID =
true;
590 if (vm.count (
"net"))
596 "Net and load/reply options are incompatible" <<
std::endl;
605 if (vm.count (
"rpc_ip"))
608 vm[
"rpc_ip"].as<std::string>());
616 if (endpoint->port() == 0)
618 std::cerr <<
"No port specified in rpc_ip.\n";
619 if (vm.count (
"rpc_port"))
621 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
624 endpoint = endpoint->at_port(
625 vm[
"rpc_port"].as<std::uint16_t>());
626 if (endpoint->port() == 0)
639 config->rpc_ip = std::move(*endpoint);
642 if (vm.count (
"quorum"))
646 config->VALIDATION_QUORUM = vm[
"quorum"].as <
std::size_t> ();
654 std::cerr <<
"Invalid value specified for --quorum ("
655 << e.
what() <<
")\n";
664 if (vm.count (
"quiet"))
666 else if (vm.count (
"verbose"))
669 auto logs = std::make_unique<Logs>(thresh);
672 if (!vm.count (
"parameters"))
676 if (config->had_trailing_comments())
678 JLOG(logs->journal(
"Application").warn()) <<
679 "Trailing comments were seen in your config file. " <<
680 "The treatment of inline/trailing comments has changed recently. " <<
681 "Any `#` characters NOT intended to delimit comments should be " <<
690 if (
HaveSustain() && !vm.count (
"fg") && !config->standalone())
698 if (vm.count (
"debug"))
705 logs->journal(
"TimeKeeper"));
710 std::move(timeKeeper));
722 app->logs().journal(
"Application")))
749 int main (
int argc,
char** argv)
770 atexit(&google::protobuf::ShutdownProtobufLibrary);
772 auto const result (ripple::run (argc, argv));