20#include <xrpld/app/main/Application.h>
21#include <xrpld/app/main/DBInit.h>
22#include <xrpld/app/rdb/Vacuum.h>
23#include <xrpld/core/Config.h>
24#include <xrpld/core/ConfigSections.h>
25#include <xrpld/core/TimeKeeper.h>
26#include <xrpld/net/RPCCall.h>
27#include <xrpld/rpc/RPCHandler.h>
28#include <xrpl/basics/Log.h>
29#include <xrpl/basics/StringUtilities.h>
30#include <xrpl/basics/contract.h>
31#include <xrpl/beast/clock/basic_seconds_clock.h>
32#include <xrpl/beast/core/CurrentThreadName.h>
33#include <xrpl/json/to_string.h>
34#include <xrpl/protocol/BuildInfo.h>
35#include <xrpl/resource/Fees.h>
38#include <test/unit_test/multi_runner.h>
39#include <xrpl/beast/unit_test/match.h>
42#include <google/protobuf/stubs/common.h>
44#include <boost/filesystem.hpp>
45#include <boost/predef.h>
46#include <boost/process.hpp>
47#include <boost/program_options.hpp>
61#if !BOOST_OS_LINUX && !BOOST_OS_WINDOWS && !BOOST_OS_MACOS
62#error Supported platforms are: Linux, Windows and MacOS
66#if (BOOST_OS_LINUX && (BOOST_OS_WINDOWS || BOOST_OS_MACOS)) || \
67 (BOOST_OS_MACOS && (BOOST_OS_WINDOWS || BOOST_OS_LINUX)) || \
68 (BOOST_OS_WINDOWS && (BOOST_OS_LINUX || BOOST_OS_MACOS))
69#error Multiple supported platforms appear active at once
73#include "antithesis_instrumentation.h"
76namespace po = boost::program_options;
89 if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
92 if (rl.rlim_cur == RLIM_INFINITY)
102 rl.rlim_cur = needed;
104 if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
111 j.
fatal() <<
"Insufficient number of file descriptors: " << needed
112 <<
" are needed, but only " <<
available <<
" are available.";
114 std::cerr <<
"Insufficient number of file descriptors: " << needed
116 <<
" are available.\n";
129 <<
systemName() <<
"d [options] <command> <params>\n"
132 " account_currencies <account> [<ledger>]\n"
133 " account_info <account>|<key> [<ledger>]\n"
134 " account_lines <account> <account>|\"\" [<ledger>]\n"
135 " account_channels <account> <account>|\"\" [<ledger>]\n"
136 " account_objects <account> [<ledger>]\n"
137 " account_offers <account>|<account_public_key> [<ledger>]\n"
138 " account_tx accountID [ledger_index_min [ledger_index_max "
141 " book_changes [<ledger hash|id>]\n"
142 " book_offers <taker_pays> <taker_gets> [<taker [<ledger> "
143 "[<limit> [<proof> [<marker>]]]]]\n"
144 " can_delete [<ledgerid>|<ledgerhash>|now|always|never]\n"
145 " channel_authorize <private_key> <channel_id> <drops>\n"
146 " channel_verify <public_key> <channel_id> <drops> <signature>\n"
147 " connect <ip> [<port>]\n"
149 " deposit_authorized <source_account> <destination_account> "
150 "[<ledger> [<credentials>, ...]]\n"
151 " feature [<feature> [accept|reject]]\n"
152 " fetch_info [clear]\n"
153 " gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ "
156 " json <method> <json>\n"
157 " ledger [<id>|current|closed|validated] [full]\n"
162 " ledger_request <ledger>\n"
163 " log_level [[<partition>] <severity>]\n"
165 " manifest <public_key>\n"
169 " peer_reservations_add <public_key> [<description>]\n"
170 " peer_reservations_del <public_key>\n"
171 " peer_reservations_list\n"
173 " ripple_path_find <json> [<ledger>]\n"
174 " server_definitions [<hash>]\n"
175 " server_info [counters]\n"
176 " server_state [counters]\n"
177 " sign <private_key> <tx_json> [offline]\n"
178 " sign_for <signer_address> <signer_private_key> <tx_json> "
181 " simulate [<tx_blob>|<tx_json>] [<binary>]\n"
182 " submit <tx_blob>|[<private_key> <tx_json>]\n"
183 " submit_multisigned <tx_json>\n"
185 " validation_create [<seed>|<pass_phrase>|<key>]\n"
188 " validator_list_sites\n"
190 " wallet_propose [<passphrase>]\n";
205 explicit multi_selector(
std::string const& patterns =
"")
208 boost::split(v, patterns, boost::algorithm::is_any_of(
","));
212 if (selectors_.empty() || !s.empty())
213 selectors_.emplace_back(
214 beast::unit_test::selector::automatch, s);
221 for (
auto& sel : selectors_)
230 return selectors_.size();
238template <
class Runner>
240anyMissing(Runner& runner, multi_selector
const& pred)
242 if (runner.tests() == 0)
244 runner.add_failures(1);
248 if (runner.suites() < pred.size())
250 auto const missing = pred.size() - runner.suites();
251 runner.add_failures(missing);
253 <<
" filters did not match any existing test suites"
277 if (!child && num_jobs == 1)
282 child_runner.arg(argument);
283 multi_selector pred(pattern);
284 auto const any_failed =
285 child_runner.run_multi(pred) || anyMissing(child_runner, pred);
300 for (
int i = 1; i < argc; ++i)
307 boost::process::exe = exe_name, boost::process::args = args);
309 int bad_child_exits = 0;
310 int terminated_child_exits = 0;
311 for (
auto& c : children)
323 ++terminated_child_exits;
328 anyMissing(parent_runner, multi_selector(pattern));
330 if (parent_runner.
any_failed() || bad_child_exits)
339 auto const anyFailed =
runner.run_multi(multi_selector(pattern));
358 po::variables_map vm;
362 importText +=
"Import an existing node database (specified in the [";
364 importText +=
"] configuration file section) into the current ";
365 importText +=
"node database (specified in the [";
367 importText +=
"] configuration file section).";
372 po::options_description gen(
"General Options");
374 "conf", po::value<std::string>(),
"Specify the configuration file.")(
375 "debug",
"Enable normally suppressed debug logging")(
376 "help,h",
"Display this message.")(
377 "newnodeid",
"Generate a new node identity for this server.")(
379 po::value<std::string>(),
380 "Specify the node identity for this server.")(
382 po::value<std::size_t>(),
383 "Override the minimum validation quorum.")(
384 "silent",
"No output to the console after startup.")(
385 "standalone,a",
"Run with no peers.")(
"verbose,v",
"Verbose logging.")
387 (
"force_ledger_present_range",
388 po::value<std::string>(),
389 "Specify the range of present ledgers for testing purposes. Min and "
390 "max values are comma separated.")(
391 "version",
"Display the build version.");
393 po::options_description data(
"Ledger/Data Options");
394 data.add_options()(
"import", importText.
c_str())(
396 po::value<std::string>(),
397 "Load the specified ledger and start from the value given.")(
399 po::value<std::string>(),
400 "Load the specified ledger file.")(
401 "load",
"Load the current ledger from the local DB.")(
402 "net",
"Get the initial ledger from the network.")(
403 "replay",
"Replay a ledger close.")(
405 po::value<std::string>(),
406 "Trap a specific transaction during replay.")(
407 "start",
"Start from a fresh Ledger.")(
408 "vacuum",
"VACUUM the transaction db.")(
409 "valid",
"Consider the initial ledger a valid network ledger.");
411 po::options_description
rpc(
"RPC Client Options");
414 "Perform rpc command - see below for available commands. "
415 "This is assumed if any positional parameters are provided.")(
417 po::value<std::string>(),
418 "Specify the IP address for RPC command. "
419 "Format: <ip-address>[':'<port-number>]")(
421 po::value<std::uint16_t>(),
422 "DEPRECATED: include with rpc_ip instead. "
423 "Specify the port number for RPC command.");
426 po::options_description test(
"Unit Test Options");
429 "Suppress test suite messages, "
430 "including suite/case name (at start) and test log messages.")(
432 po::value<std::string>()->implicit_value(
""),
433 "Perform unit tests. The optional argument specifies one or "
434 "more comma-separated selectors. Each selector specifies a suite name, "
435 "suite name prefix, full-name (lib.module.suite), module, or library "
436 "(checked in that order).")(
438 po::value<std::string>()->implicit_value(
""),
439 "Supplies an argument string to unit tests. If provided, this argument "
440 "is made available to each suite that runs. Interpretation of the "
441 "argument is handled individually by any suite that accesses it -- "
442 "as such, it typically only make sense to provide this when running "
445 "Use IPv6 localhost when running unittests (default is IPv4).")(
447 "Force unit test log message output. Only useful in combination with "
448 "--quiet, in which case log messages will print but suite/case names "
451 po::value<std::size_t>(),
452 "Number of unittest jobs to run in parallel (child processes).");
457 po::options_description hidden(
"Hidden Options");
458 hidden.add_options()(
460 po::value<vector<string>>(),
461 "Specify rpc command and parameters. This option must be repeated "
462 "for each command/param. Positional parameters also serve this "
464 "so this option is not needed for users")
467 "For internal use only when spawning child unit test processes.")
469 (
"unittest",
"Disabled in this build.")(
470 "unittest-child",
"Disabled in this build.")
472 (
"fg",
"Deprecated: server always in foreground mode.");
475 po::positional_options_description p;
476 p.add(
"parameters", -1);
478 po::options_description
all;
487 po::options_description desc;
500 po::command_line_parser(argc, argv)
514 if (vm.count(
"help"))
520 if (vm.count(
"version"))
528 if (vm.count(
"unittest") || vm.count(
"unittest-child"))
538 if (vm.count(
"unittest"))
542 if (vm.count(
"unittest-arg"))
546 bool unittestChild =
false;
547 if (vm.count(
"unittest-jobs"))
548 numJobs =
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
549 unittestChild = bool(vm.count(
"unittest-child"));
552 vm[
"unittest"].as<std::string>(),
554 bool(vm.count(
"quiet")),
555 bool(vm.count(
"unittest-log")),
557 bool(vm.count(
"unittest-ipv6")),
565 if (vm.count(
"unittest-jobs"))
568 std::cerr <<
"rippled: '--unittest-jobs' specified without "
570 std::cerr <<
"To run the unit tests the '--unittest' option must "
577 auto config = std::make_unique<Config>();
585 bool(vm.count(
"quiet")),
586 bool(vm.count(
"silent")),
587 bool(vm.count(
"standalone")));
589 if (vm.count(
"vacuum"))
591 if (config->standalone())
593 std::cerr <<
"vacuum not applicable in standalone mode.\n";
605 std::cerr <<
"exception " << e.
what() <<
" in function " << __func__
613 if (vm.contains(
"force_ledger_present_range"))
621 vm[
"force_ledger_present_range"].as<std::string>(),
622 boost::algorithm::is_any_of(
","));
624 for (
auto& s : strVec)
638 "Invalid force_ledger_present_range parameter");
640 config->FORCED_LEDGER_RANGE_PRESENT.emplace(r[0], r[1]);
645 "Invalid force_ledger_present_range parameter");
650 std::cerr <<
"invalid 'force_ledger_present_range' parameter. The "
651 "parameter must be two numbers separated by a comma. "
652 "The first number must be <= the second."
658 if (vm.count(
"start"))
663 if (vm.count(
"import"))
664 config->doImport =
true;
666 if (vm.count(
"ledger"))
668 config->START_LEDGER = vm[
"ledger"].as<
std::string>();
669 if (vm.count(
"replay"))
672 if (vm.count(
"trap_tx_hash"))
678 config->TRAP_TX_HASH = tmp;
682 std::cerr <<
"Trap parameter was ill-formed, expected "
683 "valid transaction hash but received: "
692 else if (vm.count(
"ledgerfile"))
694 config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
697 else if (vm.count(
"load") || config->FAST_LOAD)
702 if (vm.count(
"trap_tx_hash") && vm.count(
"replay") == 0)
704 std::cerr <<
"Cannot use trap option without replay option"
709 if (vm.count(
"net") && !config->FAST_LOAD)
714 std::cerr <<
"Net and load/replay options are incompatible"
722 if (vm.count(
"valid"))
724 config->START_VALID =
true;
729 if (vm.count(
"rpc_ip"))
732 vm[
"rpc_ip"].as<std::string>());
740 if (endpoint->port() == 0)
742 std::cerr <<
"No port specified in rpc_ip.\n";
743 if (vm.count(
"rpc_port"))
745 std::cerr <<
"WARNING: using deprecated rpc_port param.\n";
749 endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
750 if (endpoint->port() == 0)
763 config->rpc_ip = std::move(*endpoint);
766 if (vm.count(
"quorum"))
770 config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
778 std::cerr <<
"Invalid value specified for --quorum (" << e.
what()
788 if (vm.count(
"quiet"))
790 else if (vm.count(
"verbose"))
793 auto logs = std::make_unique<Logs>(thresh);
796 if (!vm.count(
"parameters"))
800 if (config->had_trailing_comments())
802 JLOG(logs->journal(
"Application").warn())
803 <<
"Trailing comments were seen in your config file. "
804 <<
"The treatment of inline/trailing comments has changed "
806 <<
"Any `#` characters NOT intended to delimit comments should "
808 <<
"preceded by a \\";
816 if (vm.count(
"debug"))
820 std::move(config), std::move(logs), std::make_unique<TimeKeeper>());
828 app->fdRequired(), app->logs().journal(
"Application")))
850main(
int argc,
char** argv)
870 atexit(&google::protobuf::ShutdownProtobufLibrary);
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
A generic endpoint for log messages.
Unit test runner interface.
void arg(std::string const &s)
Set the argument string.
Associates a unit test type with metadata.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Set the expected result code for a JTx The test will fail if the code doesn't match.
A class to run a subset of unit tests.
Manager for children running unit tests.
void add_failures(std::size_t failures)
T emplace_back(T... args)
A namespace for easy access to logging severity values.
Severity
Severity level / threshold of a Journal message.
void setCurrentThreadName(std::string_view newThreadName)
Changes the name of the caller thread.
std::string const & getVersionString()
Server version.
int fromCommandLine(Config const &config, const std::vector< std::string > &vCmd, Logs &logs)
std::atomic< bool > envUseIPv4
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static std::string const & systemName()
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
void printHelp(const po::options_description &desc)
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
int run(int argc, char **argv)
bool adjustDescriptorLimit(int needed, beast::Journal j)
std::unique_ptr< beast::Journal::Sink > setDebugLogSink(std::unique_ptr< beast::Journal::Sink > sink)
Set the sink for the debug journal.
bool doVacuumDB(DatabaseCon::Setup const &setup, beast::Journal j)
doVacuumDB Creates, initialises, and performs cleanup on a database.
static std::string nodeDatabase()
static std::string importNodeDatabase()