20#include <xrpld/app/main/Application.h> 
   21#include <xrpld/app/rdb/Vacuum.h> 
   22#include <xrpld/core/Config.h> 
   23#include <xrpld/core/ConfigSections.h> 
   24#include <xrpld/core/TimeKeeper.h> 
   25#include <xrpld/rpc/RPCCall.h> 
   27#include <xrpl/basics/Log.h> 
   28#include <xrpl/beast/core/CurrentThreadName.h> 
   29#include <xrpl/protocol/BuildInfo.h> 
   31#include <boost/asio/io_context.hpp> 
   32#include <boost/process/v1/args.hpp> 
   33#include <boost/process/v1/child.hpp> 
   34#include <boost/process/v1/exe.hpp> 
   37#include <test/unit_test/multi_runner.h> 
   39#include <xrpl/beast/unit_test/match.h> 
   41#include <boost/algorithm/string.hpp> 
   42#include <boost/program_options.hpp> 
   44#include <google/protobuf/stubs/common.h> 
   58#if !BOOST_OS_LINUX && !BOOST_OS_WINDOWS && !BOOST_OS_MACOS 
   59#error Supported platforms are: Linux, Windows and MacOS 
   63#if (BOOST_OS_LINUX && (BOOST_OS_WINDOWS || BOOST_OS_MACOS)) || \ 
   64    (BOOST_OS_MACOS && (BOOST_OS_WINDOWS || BOOST_OS_LINUX)) || \ 
   65    (BOOST_OS_WINDOWS && (BOOST_OS_LINUX || BOOST_OS_MACOS)) 
   66#error Multiple supported platforms appear active at once 
   70#include "antithesis_instrumentation.h" 
   73namespace po = boost::program_options;
 
   86    if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
 
   89        if (rl.rlim_cur == RLIM_INFINITY)
 
  101            if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
 
  108        j.
fatal() << 
"Insufficient number of file descriptors: " << needed
 
  109                  << 
" are needed, but only " << 
available << 
" are available.";
 
  111        std::cerr << 
"Insufficient number of file descriptors: " << needed
 
  113                  << 
" are available.\n";
 
 
  126        << 
systemName() << 
"d [options] <command> <params>\n" 
  129           "     account_currencies <account> [<ledger>]\n" 
  130           "     account_info <account>|<key> [<ledger>]\n" 
  131           "     account_lines <account> <account>|\"\" [<ledger>]\n" 
  132           "     account_channels <account> <account>|\"\" [<ledger>]\n" 
  133           "     account_objects <account> [<ledger>]\n" 
  134           "     account_offers <account>|<account_public_key> [<ledger>]\n" 
  135           "     account_tx accountID [ledger_index_min [ledger_index_max " 
  138           "     book_changes [<ledger hash|id>]\n" 
  139           "     book_offers <taker_pays> <taker_gets> [<taker [<ledger> " 
  140           "[<limit> [<proof> [<marker>]]]]]\n" 
  141           "     can_delete [<ledgerid>|<ledgerhash>|now|always|never]\n" 
  142           "     channel_authorize <private_key> <channel_id> <drops>\n" 
  143           "     channel_verify <public_key> <channel_id> <drops> <signature>\n" 
  144           "     connect <ip> [<port>]\n" 
  146           "     deposit_authorized <source_account> <destination_account> " 
  147           "[<ledger> [<credentials>, ...]]\n" 
  148           "     feature [<feature> [accept|reject]]\n" 
  149           "     fetch_info [clear]\n" 
  150           "     gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ " 
  153           "     json <method> <json>\n" 
  154           "     ledger [<id>|current|closed|validated] [full]\n" 
  159           "     ledger_request <ledger>\n" 
  160           "     log_level [[<partition>] <severity>]\n" 
  162           "     manifest <public_key>\n" 
  166           "     peer_reservations_add <public_key> [<description>]\n" 
  167           "     peer_reservations_del <public_key>\n" 
  168           "     peer_reservations_list\n" 
  170           "     ripple_path_find <json> [<ledger>]\n" 
  171           "     server_definitions [<hash>]\n" 
  172           "     server_info [counters]\n" 
  173           "     server_state [counters]\n" 
  174           "     sign <private_key> <tx_json> [offline]\n" 
  175           "     sign_for <signer_address> <signer_private_key> <tx_json> " 
  176           "[offline] [<signature_field>]\n" 
  178           "     simulate [<tx_blob>|<tx_json>] [<binary>]\n" 
  179           "     submit <tx_blob>|[<private_key> <tx_json>]\n" 
  180           "     submit_multisigned <tx_json>\n" 
  182           "     validation_create [<seed>|<pass_phrase>|<key>]\n" 
  185           "     validator_list_sites\n" 
  187           "     wallet_propose [<passphrase>]\n";
 
 
  202    explicit multi_selector(
std::string const& patterns = 
"")
 
  205        boost::split(v, patterns, boost::algorithm::is_any_of(
","));
 
  209            if (selectors_.empty() || !s.empty())
 
  210                selectors_.emplace_back(
 
  211                    beast::unit_test::selector::automatch, s);
 
  218        for (
auto& sel : selectors_)
 
  227        return selectors_.
size();
 
  235template <
class Runner>
 
  237anyMissing(Runner& runner, multi_selector 
const& pred)
 
  239    if (runner.tests() == 0)
 
  241        runner.add_failures(1);
 
  245    if (runner.suites() < pred.size())
 
  247        auto const missing = pred.size() - runner.suites();
 
  248        runner.add_failures(missing);
 
  250                  << 
" filters did not match any existing test suites" 
  274    if (!child && num_jobs == 1)
 
  279        child_runner.arg(argument);
 
  280        multi_selector pred(pattern);
 
  281        auto const any_failed =
 
  282            child_runner.run_multi(pred) || anyMissing(child_runner, pred);
 
  297            for (
int i = 1; i < argc; ++i)
 
  304                boost::process::v1::exe = exe_name,
 
  305                boost::process::v1::args = args);
 
  307        int bad_child_exits = 0;
 
  308        int terminated_child_exits = 0;
 
  309        for (
auto& c : children)
 
  321                ++terminated_child_exits;
 
  326        anyMissing(parent_runner, multi_selector(pattern));
 
  328        if (parent_runner.
any_failed() || bad_child_exits)
 
  337        auto const anyFailed = 
runner.run_multi(multi_selector(pattern));
 
  356    po::variables_map vm;
 
  360        importText += 
"Import an existing node database (specified in the [";
 
  362        importText += 
"] configuration file section) into the current ";
 
  363        importText += 
"node database (specified in the [";
 
  365        importText += 
"] configuration file section).";
 
  370    po::options_description gen(
"General Options");
 
  372        "conf", po::value<std::string>(), 
"Specify the configuration file.")(
 
  373        "debug", 
"Enable normally suppressed debug logging")(
 
  374        "help,h", 
"Display this message.")(
 
  375        "newnodeid", 
"Generate a new node identity for this server.")(
 
  377        po::value<std::string>(),
 
  378        "Specify the node identity for this server.")(
 
  380        po::value<std::size_t>(),
 
  381        "Override the minimum validation quorum.")(
 
  382        "silent", 
"No output to the console after startup.")(
 
  383        "standalone,a", 
"Run with no peers.")(
"verbose,v", 
"Verbose logging.")
 
  385        (
"force_ledger_present_range",
 
  386         po::value<std::string>(),
 
  387         "Specify the range of present ledgers for testing purposes. Min and " 
  388         "max values are comma separated.")(
 
  389            "version", 
"Display the build version.");
 
  391    po::options_description data(
"Ledger/Data Options");
 
  392    data.add_options()(
"import", importText.
c_str())(
 
  394        po::value<std::string>(),
 
  395        "Load the specified ledger and start from the value given.")(
 
  397        po::value<std::string>(),
 
  398        "Load the specified ledger file.")(
 
  399        "load", 
"Load the current ledger from the local DB.")(
 
  400        "net", 
"Get the initial ledger from the network.")(
 
  401        "replay", 
"Replay a ledger close.")(
 
  403        po::value<std::string>(),
 
  404        "Trap a specific transaction during replay.")(
 
  405        "start", 
"Start from a fresh Ledger.")(
 
  406        "vacuum", 
"VACUUM the transaction db.")(
 
  407        "valid", 
"Consider the initial ledger a valid network ledger.");
 
  409    po::options_description 
rpc(
"RPC Client Options");
 
  412        "Perform rpc command - see below for available commands. " 
  413        "This is assumed if any positional parameters are provided.")(
 
  415        po::value<std::string>(),
 
  416        "Specify the IP address for RPC command. " 
  417        "Format: <ip-address>[':'<port-number>]")(
 
  419        po::value<std::uint16_t>(),
 
  420        "DEPRECATED: include with rpc_ip instead. " 
  421        "Specify the port number for RPC command.");
 
  424    po::options_description test(
"Unit Test Options");
 
  427        "Suppress test suite messages, " 
  428        "including suite/case name (at start) and test log messages.")(
 
  430        po::value<std::string>()->implicit_value(
""),
 
  431        "Perform unit tests. The optional argument specifies one or " 
  432        "more comma-separated selectors. Each selector specifies a suite name, " 
  433        "suite name prefix, full-name (lib.module.suite), module, or library " 
  434        "(checked in that order).")(
 
  436        po::value<std::string>()->implicit_value(
""),
 
  437        "Supplies an argument string to unit tests. If provided, this argument " 
  438        "is made available to each suite that runs. Interpretation of the " 
  439        "argument is handled individually by any suite that accesses it -- " 
  440        "as such, it typically only make sense to provide this when running " 
  443        "Use IPv6 localhost when running unittests (default is IPv4).")(
 
  445        "Force unit test log message output. Only useful in combination with " 
  446        "--quiet, in which case log messages will print but suite/case names " 
  449        po::value<std::size_t>(),
 
  450        "Number of unittest jobs to run in parallel (child processes).");
 
  455    po::options_description hidden(
"Hidden Options");
 
  456    hidden.add_options()(
 
  458        po::value<vector<string>>(),
 
  459        "Specify rpc command and parameters. This option must be repeated " 
  460        "for each command/param. Positional parameters also serve this " 
  462        "so this option is not needed for users")
 
  465         "For internal use only when spawning child unit test processes.")
 
  467        (
"unittest", 
"Disabled in this build.")(
 
  468            "unittest-child", 
"Disabled in this build.")
 
  470            (
"fg", 
"Deprecated: server always in foreground mode.");
 
  473    po::positional_options_description p;
 
  474    p.add(
"parameters", -1);
 
  476    po::options_description 
all;
 
  485    po::options_description desc;
 
  498            po::command_line_parser(argc, argv)
 
  512    if (vm.count(
"help"))
 
  518    if (vm.count(
"version"))
 
  522#ifdef GIT_COMMIT_HASH 
  532    if (vm.count(
"unittest") || vm.count(
"unittest-child"))
 
  542    if (vm.count(
"unittest"))
 
  546        if (vm.count(
"unittest-arg"))
 
  550        bool unittestChild = 
false;
 
  551        if (vm.count(
"unittest-jobs"))
 
  552            numJobs = 
std::max(numJobs, vm[
"unittest-jobs"].as<std::size_t>());
 
  553        unittestChild = bool(vm.count(
"unittest-child"));
 
  556            vm[
"unittest"].as<std::string>(),
 
  558            bool(vm.count(
"quiet")),
 
  559            bool(vm.count(
"unittest-log")),
 
  561            bool(vm.count(
"unittest-ipv6")),
 
  569        if (vm.count(
"unittest-jobs"))
 
  572            std::cerr << 
"rippled: '--unittest-jobs' specified without " 
  574            std::cerr << 
"To run the unit tests the '--unittest' option must " 
  589        bool(vm.count(
"quiet")),
 
  590        bool(vm.count(
"silent")),
 
  591        bool(vm.count(
"standalone")));
 
  593    if (vm.count(
"vacuum"))
 
  595        if (config->standalone())
 
  597            std::cerr << 
"vacuum not applicable in standalone mode.\n";
 
  609            std::cerr << 
"exception " << e.
what() << 
" in function " << __func__
 
  617    if (vm.contains(
"force_ledger_present_range"))
 
  625                    vm[
"force_ledger_present_range"].as<std::string>(),
 
  626                    boost::algorithm::is_any_of(
","));
 
  628                for (
auto& s : strVec)
 
  642                        "Invalid force_ledger_present_range parameter");
 
  644                config->FORCED_LEDGER_RANGE_PRESENT.emplace(r[0], r[1]);
 
  649                    "Invalid force_ledger_present_range parameter");
 
  654            std::cerr << 
"invalid 'force_ledger_present_range' parameter. The " 
  655                         "parameter must be two numbers separated by a comma. " 
  656                         "The first number must be <= the second." 
  662    if (vm.count(
"start"))
 
  667    if (vm.count(
"import"))
 
  668        config->doImport = 
true;
 
  670    if (vm.count(
"ledger"))
 
  672        config->START_LEDGER = vm[
"ledger"].as<
std::string>();
 
  673        if (vm.count(
"replay"))
 
  676            if (vm.count(
"trap_tx_hash"))
 
  682                    config->TRAP_TX_HASH = tmp;
 
  686                    std::cerr << 
"Trap parameter was ill-formed, expected " 
  687                                 "valid transaction hash but received: " 
  696    else if (vm.count(
"ledgerfile"))
 
  698        config->START_LEDGER = vm[
"ledgerfile"].as<
std::string>();
 
  701    else if (vm.count(
"load") || config->FAST_LOAD)
 
  706    if (vm.count(
"trap_tx_hash") && vm.count(
"replay") == 0)
 
  708        std::cerr << 
"Cannot use trap option without replay option" 
  713    if (vm.count(
"net") && !config->FAST_LOAD)
 
  718            std::cerr << 
"Net and load/replay options are incompatible" 
  726    if (vm.count(
"valid"))
 
  728        config->START_VALID = 
true;
 
  733    if (vm.count(
"rpc_ip"))
 
  736            vm[
"rpc_ip"].as<std::string>());
 
  744        if (endpoint->port() == 0)
 
  746            std::cerr << 
"No port specified in rpc_ip.\n";
 
  747            if (vm.count(
"rpc_port"))
 
  749                std::cerr << 
"WARNING: using deprecated rpc_port param.\n";
 
  753                        endpoint->at_port(vm[
"rpc_port"].as<std::uint16_t>());
 
  754                    if (endpoint->port() == 0)
 
  767        config->rpc_ip = std::move(*endpoint);
 
  770    if (vm.count(
"quorum"))
 
  774            config->VALIDATION_QUORUM = vm[
"quorum"].as<
std::size_t>();
 
  782            std::cerr << 
"Invalid value specified for --quorum (" << e.
what()
 
  792    if (vm.count(
"quiet"))
 
  794    else if (vm.count(
"verbose"))
 
  800    if (!vm.count(
"parameters"))
 
  804        if (config->had_trailing_comments())
 
  806            JLOG(logs->journal(
"Application").warn())
 
  807                << 
"Trailing comments were seen in your config file. " 
  808                << 
"The treatment of inline/trailing comments has changed " 
  810                << 
"Any `#` characters NOT intended to delimit comments should " 
  812                << 
"preceded by a \\";
 
  820        if (vm.count(
"debug"))
 
  832                app->fdRequired(), app->logs().journal(
"Application")))
 
 
  854main(
int argc, 
char** argv)
 
  874    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, std::vector< std::string > const &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)
 
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.
 
void printHelp(po::options_description const &desc)
 
static std::string nodeDatabase()
 
static std::string importNodeDatabase()