mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
460 lines
15 KiB
C++
460 lines
15 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
Copyright (c) 2011-2013, OpenCoin, Inc.
|
|
*/
|
|
//==============================================================================
|
|
|
|
namespace po = boost::program_options;
|
|
|
|
void setupServer ()
|
|
{
|
|
#ifdef RLIMIT_NOFILE
|
|
struct rlimit rl;
|
|
if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
|
|
{
|
|
if (rl.rlim_cur != rl.rlim_max)
|
|
{
|
|
rl.rlim_cur = rl.rlim_max;
|
|
setrlimit(RLIMIT_NOFILE, &rl);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
getApp().setup ();
|
|
}
|
|
|
|
void startServer ()
|
|
{
|
|
//
|
|
// Execute start up rpc commands.
|
|
//
|
|
if (getConfig ().RPC_STARTUP.isArray ())
|
|
{
|
|
for (int i = 0; i != getConfig ().RPC_STARTUP.size (); ++i)
|
|
{
|
|
const Json::Value& jvCommand = getConfig ().RPC_STARTUP[i];
|
|
|
|
if (!getConfig ().QUIET)
|
|
Log::out() << "Startup RPC: " << jvCommand;
|
|
|
|
RPCHandler rhHandler (&getApp().getOPs ());
|
|
|
|
// VFALCO TODO Clean up this magic number
|
|
LoadType loadType = LT_RPCReference;
|
|
Json::Value jvResult = rhHandler.doCommand (jvCommand, RPCHandler::ADMIN, &loadType);
|
|
|
|
if (!getConfig ().QUIET)
|
|
Log::out() << "Result: " << jvResult;
|
|
}
|
|
}
|
|
|
|
getApp().run (); // Blocks till we get a stop RPC.
|
|
}
|
|
|
|
void printHelp (const po::options_description& desc)
|
|
{
|
|
using namespace std;
|
|
|
|
cerr << SYSTEM_NAME "d [options] <command> <params>" << endl;
|
|
|
|
cerr << desc << endl;
|
|
|
|
cerr << "Commands: " << endl;
|
|
cerr << " account_info <account>|<nickname>|<seed>|<pass_phrase>|<key> [<ledger>] [strict]" << endl;
|
|
cerr << " account_lines <account> <account>|\"\" [<ledger>]" << endl;
|
|
cerr << " account_offers <account>|<nickname>|<account_public_key> [<ledger>]" << endl;
|
|
cerr << " account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] [count] [descending]" << endl;
|
|
cerr << " book_offers <taker_pays> <taker_gets> [<taker [<ledger> [<limit> [<proof> [<marker>]]]]]" << endl;
|
|
cerr << " connect <ip> [<port>]" << endl;
|
|
cerr << " consensus_info" << endl;
|
|
#if ENABLE_INSECURE
|
|
cerr << " data_delete <key>" << endl;
|
|
cerr << " data_fetch <key>" << endl;
|
|
cerr << " data_store <key> <value>" << endl;
|
|
#endif
|
|
cerr << " get_counts" << endl;
|
|
cerr << " json <method> <json>" << endl;
|
|
cerr << " ledger [<id>|current|closed|validated] [full]" << endl;
|
|
cerr << " ledger_accept" << endl;
|
|
cerr << " ledger_closed" << endl;
|
|
cerr << " ledger_current" << endl;
|
|
cerr << " ledger_header <ledger>" << endl;
|
|
cerr << " logrotate " << endl;
|
|
cerr << " peers" << endl;
|
|
cerr << " proof_create [<difficulty>] [<secret>]" << endl;
|
|
cerr << " proof_solve <token>" << endl;
|
|
cerr << " proof_verify <token> <solution> [<difficulty>] [<secret>]" << endl;
|
|
cerr << " random" << endl;
|
|
cerr << " ripple ..." << endl;
|
|
cerr << " ripple_path_find <json> [<ledger>]" << endl;
|
|
// cerr << " send <seed> <paying_account> <account_id> <amount> [<currency>] [<send_max>] [<send_currency>]" << endl;
|
|
cerr << " stop" << endl;
|
|
cerr << " tx <id>" << endl;
|
|
cerr << " unl_add <domain>|<public> [<comment>]" << endl;
|
|
cerr << " unl_delete <domain>|<public_key>" << endl;
|
|
cerr << " unl_list" << endl;
|
|
cerr << " unl_load" << endl;
|
|
cerr << " unl_network" << endl;
|
|
cerr << " unl_reset" << endl;
|
|
cerr << " validation_create [<seed>|<pass_phrase>|<key>]" << endl;
|
|
cerr << " validation_seed [<seed>|<pass_phrase>|<key>]" << endl;
|
|
cerr << " wallet_add <regular_seed> <paying_account> <master_seed> [<initial_funds>] [<account_annotation>]" << endl;
|
|
cerr << " wallet_accounts <seed>" << endl;
|
|
cerr << " wallet_claim <master_seed> <regular_seed> [<source_tag>] [<account_annotation>]" << endl;
|
|
cerr << " wallet_seed [<seed>|<passphrase>|<passkey>]" << endl;
|
|
cerr << " wallet_propose [<passphrase>]" << endl;
|
|
|
|
// Transaction helpers (that were removed):
|
|
// cerr << " account_domain_set <seed> <paying_account> [<domain>]" << endl;
|
|
// cerr << " account_email_set <seed> <paying_account> [<email_address>]" << endl;
|
|
// cerr << " account_rate_set <seed> <paying_account> <rate>" << endl;
|
|
// cerr << " account_wallet_set <seed> <paying_account> [<wallet_hash>]" << endl;
|
|
// cerr << " nickname_info <nickname>" << endl;
|
|
// cerr << " nickname_set <seed> <paying_account> <nickname> [<offer_minimum>] [<authorization>]" << endl;
|
|
// cerr << " offer_create <seed> <paying_account> <taker_pays_amount> <taker_pays_currency> <taker_pays_issuer> <takers_gets_amount> <takers_gets_currency> <takers_gets_issuer> <expires> [passive]" << endl;
|
|
// cerr << " offer_cancel <seed> <paying_account> <sequence>" << endl;
|
|
// cerr << " password_fund <seed> <paying_account> [<account>]" << endl;
|
|
// cerr << " password_set <master_seed> <regular_seed> [<account>]" << endl;
|
|
// cerr << " trust_set <seed> <paying_account> <destination_account> <limit_amount> <currency> [<quality_in>] [<quality_out>]" << endl;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// OUr custom unit test runner
|
|
//
|
|
class RippleUnitTests : public UnitTests
|
|
{
|
|
public:
|
|
explicit RippleUnitTests (bool shouldLog)
|
|
: m_shouldLog (shouldLog)
|
|
{
|
|
// VFALCO NOTE It sucks that we have to do this but some
|
|
// code demands the Application object exists.
|
|
//
|
|
// TODO To find out who, just change the #if 1 to #if 0
|
|
#if 1
|
|
setupConfigForUnitTests (&getConfig ());
|
|
|
|
getApp ();
|
|
#endif
|
|
|
|
setAssertOnFailure (false);
|
|
}
|
|
|
|
void logMessage (String const& message)
|
|
{
|
|
if (m_shouldLog)
|
|
Log::out () << message.toStdString ();
|
|
}
|
|
|
|
private:
|
|
void setupConfigForUnitTests (Config* config)
|
|
{
|
|
config->nodeDatabase = parseDelimitedKeyValueString ("type=memory");
|
|
config->ephemeralNodeDatabase = StringPairArray ();
|
|
config->importNodeDatabase = StringPairArray ();
|
|
}
|
|
|
|
private:
|
|
bool const m_shouldLog;
|
|
};
|
|
|
|
static int runUnitTests (String const& whichTests, String const& format)
|
|
{
|
|
bool const shouldLog = format != "junit";
|
|
|
|
if (format != "junit" && format != "text" && format != "")
|
|
{
|
|
String s;
|
|
s << "Warning, unknown unittest-format='" << format << "'";
|
|
Log::out () << s.toStdString ();
|
|
}
|
|
|
|
RippleUnitTests tr (shouldLog);
|
|
|
|
if (whichTests == "")
|
|
{
|
|
tr.runAllTests ();
|
|
}
|
|
else
|
|
{
|
|
tr.runTestsByName (whichTests);
|
|
}
|
|
|
|
if (format == "junit")
|
|
{
|
|
UnitTestUtilities::JUnitXMLFormatter f (tr);
|
|
|
|
String const s = f.createDocumentString ();
|
|
|
|
Log::out () << s.toStdString ();
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
return tr.anyTestsFailed () ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int rippleMain (int argc, char** argv)
|
|
{
|
|
//
|
|
// These debug heap calls do nothing in release or non Visual Studio builds.
|
|
//
|
|
|
|
// Checks the heap at every allocation and deallocation (slow).
|
|
//
|
|
//Debug::setAlwaysCheckHeap (false);
|
|
|
|
// Keeps freed memory blocks and fills them with a guard value.
|
|
//
|
|
//Debug::setHeapDelayedFree (false);
|
|
|
|
// At exit, reports all memory blocks which have not been freed.
|
|
//
|
|
#if 1
|
|
Debug::setHeapReportLeaks (false);
|
|
|
|
#else
|
|
// This is some temporary leak checking test code
|
|
//
|
|
Debug::setHeapReportLeaks (false);
|
|
|
|
//malloc (512); // Any leaks before this line in the output are from static initializations.
|
|
|
|
ThreadWithCallQueue t ("test");
|
|
GlobalPagedFreeStore::getInstance ();
|
|
t.start ();
|
|
|
|
return 0;
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
setCallingThreadName ("main");
|
|
int iResult = 0;
|
|
po::variables_map vm; // Map of options.
|
|
|
|
String importDescription;
|
|
{
|
|
importDescription <<
|
|
"Import an existing node database (specified in the " <<
|
|
"[" << ConfigSection::importNodeDatabase () << "] configuration file section) "
|
|
"into the current node database (specified in the " <<
|
|
"[" << ConfigSection::nodeDatabase () << "] configuration file section). ";
|
|
}
|
|
|
|
// VFALCO TODO Replace boost program options with something from Beast.
|
|
//
|
|
// Set up option parsing.
|
|
//
|
|
po::options_description desc ("General Options");
|
|
desc.add_options ()
|
|
("help,h", "Display this message.")
|
|
("conf", po::value<std::string> (), "Specify the configuration file.")
|
|
("rpc", "Perform rpc command (default).")
|
|
("rpc_ip", po::value <std::string> (), "Specify the IP address for RPC command. Format: <ip-address>[':'<port-number>]")
|
|
("rpc_port", po::value <int> (), "Specify the port number for RPC command.")
|
|
("standalone,a", "Run with no peers.")
|
|
("testnet,t", "Run in test net mode.")
|
|
("unittest,u", po::value <std::string> ()->implicit_value (""), "Perform unit tests.")
|
|
("unittest-format", po::value <std::string> ()->implicit_value ("text"), "Format unit test output. Choices are 'text', 'junit'")
|
|
("parameters", po::value< vector<string> > (), "Specify comma separated parameters.")
|
|
("quiet,q", "Reduce diagnotics.")
|
|
("verbose,v", "Verbose logging.")
|
|
("load", "Load the current ledger from the local DB.")
|
|
("replay","Replay a ledger close.")
|
|
("ledger", po::value<std::string> (), "Load the specified ledger and start from .")
|
|
("start", "Start from a fresh Ledger.")
|
|
("net", "Get the initial ledger from the network.")
|
|
("fg", "Run in the foreground.")
|
|
("import", importDescription.toStdString ().c_str ())
|
|
;
|
|
|
|
// Interpret positional arguments as --parameters.
|
|
po::positional_options_description p;
|
|
p.add ("parameters", -1);
|
|
|
|
// These must be added before the Application object is created
|
|
NodeStore::addBackendFactory (KeyvaDBBackendFactory::getInstance ());
|
|
NodeStore::addBackendFactory (LevelDBBackendFactory::getInstance ());
|
|
NodeStore::addBackendFactory (MemoryBackendFactory::getInstance ());
|
|
NodeStore::addBackendFactory (NullBackendFactory::getInstance ());
|
|
NodeStore::addBackendFactory (SqliteBackendFactory::getInstance ());
|
|
#if RIPPLE_HYPERLEVELDB_AVAILABLE
|
|
NodeStore::addBackendFactory (HyperLevelDBBackendFactory::getInstance ());
|
|
#endif
|
|
#if RIPPLE_MDB_AVAILABLE
|
|
NodeStore::addBackendFactory (MdbBackendFactory::getInstance ());
|
|
#endif
|
|
|
|
if (! RandomNumbers::getInstance ().initialize ())
|
|
{
|
|
Log::out() << "Unable to add system entropy";
|
|
iResult = 2;
|
|
}
|
|
|
|
if (iResult)
|
|
{
|
|
nothing ();
|
|
}
|
|
else
|
|
{
|
|
// Parse options, if no error.
|
|
try
|
|
{
|
|
po::store (po::command_line_parser (argc, argv)
|
|
.options (desc) // Parse options.
|
|
.positional (p) // Remainder as --parameters.
|
|
.run (),
|
|
vm);
|
|
po::notify (vm); // Invoke option notify functions.
|
|
}
|
|
catch (...)
|
|
{
|
|
iResult = 1;
|
|
}
|
|
}
|
|
|
|
if (iResult)
|
|
{
|
|
nothing ();
|
|
}
|
|
else if (vm.count ("help"))
|
|
{
|
|
iResult = 1;
|
|
}
|
|
|
|
// Use a watchdog process unless we're invoking a stand alone type of mode
|
|
//
|
|
if (HaveSustain ()
|
|
&& !iResult
|
|
&& !vm.count ("parameters")
|
|
&& !vm.count ("fg")
|
|
&& !vm.count ("standalone")
|
|
&& !vm.count ("unittest"))
|
|
{
|
|
std::string logMe = DoSustain (getConfig ().DEBUG_LOGFILE.string());
|
|
|
|
if (!logMe.empty ())
|
|
Log (lsWARNING) << logMe;
|
|
}
|
|
|
|
if (vm.count ("quiet"))
|
|
{
|
|
Log::setMinSeverity (lsFATAL, true);
|
|
}
|
|
else if (vm.count ("verbose"))
|
|
{
|
|
Log::setMinSeverity (lsTRACE, true);
|
|
}
|
|
else
|
|
{
|
|
Log::setMinSeverity (lsINFO, true);
|
|
}
|
|
|
|
// Run the unit tests if requested.
|
|
// The unit tests will exit the application with an appropriate return code.
|
|
//
|
|
if (vm.count ("unittest"))
|
|
{
|
|
String format;
|
|
|
|
if (vm.count ("unittest-format"))
|
|
format = vm ["unittest-format"].as <std::string> ();
|
|
|
|
return runUnitTests (vm ["unittest"].as <std::string> (), format);
|
|
}
|
|
|
|
if (!iResult)
|
|
{
|
|
getConfig ().setup (
|
|
vm.count ("conf") ? vm["conf"].as<std::string> () : "", // Config file.
|
|
!!vm.count ("testnet"), // Testnet flag.
|
|
!!vm.count ("quiet")); // Quiet flag.
|
|
|
|
if (vm.count ("standalone"))
|
|
{
|
|
getConfig ().RUN_STANDALONE = true;
|
|
getConfig ().LEDGER_HISTORY = 0;
|
|
}
|
|
}
|
|
|
|
if (vm.count ("start")) getConfig ().START_UP = Config::FRESH;
|
|
|
|
// Handle a one-time import option
|
|
//
|
|
if (vm.count ("import"))
|
|
{
|
|
String const optionString (vm ["import"].as <std::string> ());
|
|
|
|
getConfig ().importNodeDatabase = parseDelimitedKeyValueString (optionString);
|
|
}
|
|
|
|
if (vm.count ("ledger"))
|
|
{
|
|
getConfig ().START_LEDGER = vm["ledger"].as<std::string> ();
|
|
if (vm.count("replay"))
|
|
getConfig ().START_UP = Config::REPLAY;
|
|
else
|
|
getConfig ().START_UP = Config::LOAD;
|
|
}
|
|
else if (vm.count ("load"))
|
|
{
|
|
getConfig ().START_UP = Config::LOAD;
|
|
}
|
|
else if (vm.count ("net"))
|
|
{
|
|
getConfig ().START_UP = Config::NETWORK;
|
|
|
|
if (getConfig ().VALIDATION_QUORUM < 2)
|
|
getConfig ().VALIDATION_QUORUM = 2;
|
|
}
|
|
|
|
if (iResult == 0)
|
|
{
|
|
// These overrides must happen after the config file is loaded.
|
|
|
|
// Override the RPC destination IP address
|
|
//
|
|
if (vm.count ("rpc_ip"))
|
|
{
|
|
getConfig ().setRpcIpAndOptionalPort (vm ["rpc_ip"].as <std::string> ());
|
|
}
|
|
|
|
// Override the RPC destination port number
|
|
//
|
|
if (vm.count ("rpc_port"))
|
|
{
|
|
// VFALCO TODO This should be a short.
|
|
getConfig ().setRpcPort (vm ["rpc_port"].as <int> ());
|
|
}
|
|
}
|
|
|
|
if (iResult == 0)
|
|
{
|
|
if (!vm.count ("parameters"))
|
|
{
|
|
// No arguments. Run server.
|
|
setupServer ();
|
|
setCallingThreadName ("io");
|
|
startServer ();
|
|
}
|
|
else
|
|
{
|
|
// Have a RPC command.
|
|
setCallingThreadName ("rpc");
|
|
std::vector<std::string> vCmd = vm["parameters"].as<std::vector<std::string> > ();
|
|
|
|
iResult = commandLineRPC (vCmd);
|
|
}
|
|
}
|
|
|
|
if (1 == iResult && !vm.count ("quiet"))
|
|
printHelp (desc);
|
|
|
|
return iResult;
|
|
}
|