diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index 0254c344e2..04faa80ab4 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -1926,6 +1926,9 @@ + + True + True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 6560fd77ca..785b82b19a 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -2844,6 +2844,9 @@ ripple\core + + ripple\core\tests + ripple\core\tests diff --git a/doc/rippled-example.cfg b/doc/rippled-example.cfg index 9e8e6e870f..9c00ecebc8 100644 --- a/doc/rippled-example.cfg +++ b/doc/rippled-example.cfg @@ -698,7 +698,8 @@ # There are 4 book-keeping SQLite database that the server creates and # maintains. If you omit this configuration setting, it will default to # creating a directory called "db" located in the same place as your -# rippled.cfg file. +# rippled.cfg file. Partial pathnames will be considered relative to +# the location of the rippled executable. # # # diff --git a/src/ripple/app/data/DatabaseCon.cpp b/src/ripple/app/data/DatabaseCon.cpp index b13ad94435..0f77a3ef4b 100644 --- a/src/ripple/app/data/DatabaseCon.cpp +++ b/src/ripple/app/data/DatabaseCon.cpp @@ -58,7 +58,7 @@ setup_DatabaseCon (Config const& c) setup.onlineDelete = c.nodeDatabase["online_delete"].getIntValue(); setup.startUp = c.START_UP; setup.standAlone = c.RUN_STANDALONE; - setup.dataDir = c.DATA_DIR; + setup.dataDir = c.legacy ("database_path"); return setup; } diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index d9c2211c72..585399a152 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -887,7 +887,8 @@ public: { // VFALCO TODO Move all this into doSweep - boost::filesystem::space_info space = boost::filesystem::space (getConfig ().DATA_DIR); + boost::filesystem::space_info space = + boost::filesystem::space (getConfig ().legacy ("database_path")); // VFALCO TODO Give this magic constant a name and move it into a well documented header // diff --git a/src/ripple/app/misc/SHAMapStoreImp.cpp b/src/ripple/app/misc/SHAMapStoreImp.cpp index 83531abf44..27b0f9768f 100644 --- a/src/ripple/app/misc/SHAMapStoreImp.cpp +++ b/src/ripple/app/misc/SHAMapStoreImp.cpp @@ -700,7 +700,7 @@ setup_SHAMapStore (Config const& c) setup.ledgerHistory = c.LEDGER_HISTORY; setup.nodeDatabase = c.nodeDatabase; setup.ephemeralNodeDatabase = c.ephemeralNodeDatabase; - setup.databasePath = c.DATABASE_PATH; + setup.databasePath = c.legacy("database_path"); if (c.nodeDatabase["delete_batch"].isNotEmpty()) setup.deleteBatch = c.nodeDatabase["delete_batch"].getIntValue(); if (c.nodeDatabase["backOff"].isNotEmpty()) diff --git a/src/ripple/basics/BasicConfig.h b/src/ripple/basics/BasicConfig.h index 358927a65e..e8be781372 100644 --- a/src/ripple/basics/BasicConfig.h +++ b/src/ripple/basics/BasicConfig.h @@ -76,6 +76,38 @@ public: return values_; } + /** + * Set the legacy value for this section. + */ + void + legacy (std::string value) + { + if (lines_.empty ()) + lines_.emplace_back (std::move (value)); + else + { + assert (lines_.size () == 1); + lines_[0] = std::move (value); + } + } + + /** + * Get the legacy value for this section. + * + * @return The retrieved value. A section with an empty legacy value returns + an empty string. + */ + std::string + legacy () const + { + if (lines_.empty ()) + return ""; + else if (lines_.size () > 1) + throw std::runtime_error ( + "A legacy value must have exactly one line. Section: " + name_); + return lines_[0]; + } + /** Set a key/value pair. The previous value is discarded. */ @@ -150,6 +182,29 @@ public: overwrite (std::string const& section, std::string const& key, std::string const& value); + /** + * Set a value that is not a key/value pair. + * + * The value is stored as the section's first value and may be retrieved + * through section::legacy. + * + * @param section Name of the section to modify. + * @param value Contents of the legacy value. + */ + void + legacy(std::string const& section, std::string value); + + /** + * Get the legacy value of a section. A section with a + * single-line value may be retrieved as a legacy value. + * + * @param sectionName Retrieve the contents of this section's + * legacy value. + * @returun Contents of the legacy value. + */ + std::string + legacy(std::string const& sectionName) const; + friend std::ostream& operator<< (std::ostream& ss, BasicConfig const& c); @@ -157,15 +212,6 @@ public: protected: void build (IniFileSections const& ifs); - - /** Insert a legacy single section as a key/value pair. - Does nothing if the section does not exist, or does not contain - a single line that is not a key/value pair. - @deprecated - */ - void - remap (std::string const& legacy_section, - std::string const& key, std::string const& new_section); }; //------------------------------------------------------------------------------ diff --git a/src/ripple/basics/impl/BasicConfig.cpp b/src/ripple/basics/impl/BasicConfig.cpp index 7d2de96ceb..36b24ca679 100644 --- a/src/ripple/basics/impl/BasicConfig.cpp +++ b/src/ripple/basics/impl/BasicConfig.cpp @@ -106,24 +106,6 @@ BasicConfig::section (std::string const& name) const return iter->second; } -void -BasicConfig::remap (std::string const& legacy_section, - std::string const& key, std::string const& new_section) -{ - auto const iter = map_.find (legacy_section); - if (iter == map_.end()) - return; - if (iter->second.size() != 0) - return; - if (iter->second.lines().size() != 1) - return; - auto result = map_.emplace(std::piecewise_construct, - std::make_tuple(new_section), std::make_tuple(new_section)); - auto& s = result.first->second; - s.append (iter->second.lines().front()); - s.set (key, iter->second.lines().front()); -} - void BasicConfig::overwrite (std::string const& section, std::string const& key, std::string const& value) @@ -133,6 +115,18 @@ BasicConfig::overwrite (std::string const& section, std::string const& key, result.first->second.set (key, value); } +void +BasicConfig::legacy(std::string const& section, std::string value) +{ + map_[section].legacy(std::move(value)); +} + +std::string +BasicConfig::legacy(std::string const& sectionName) const +{ + return section (sectionName).legacy (); +} + void BasicConfig::build (IniFileSections const& ifs) { diff --git a/src/ripple/core/Config.h b/src/ripple/core/Config.h index 2a4771f6a2..1207a1aed5 100644 --- a/src/ripple/core/Config.h +++ b/src/ripple/core/Config.h @@ -87,10 +87,10 @@ struct SizedItem int sizes[5]; }; -// VFALCO NOTE This entire derived class is deprecated -// For new config information use the style implied -// in the base class. For existing config information -// try to refactor code to use the new style. +// This entire derived class is deprecated. +// For new config information use the style implied +// in the base class. For existing config information +// try to refactor code to use the new style. // class Config : public BasicConfig { @@ -121,20 +121,17 @@ public: /** Returns the directory from which the configuration file was loaded. */ beast::File getConfigDir () const; - /** Returns the directory in which the current database files are located. */ - beast::File getDatabaseDir () const; - /** Returns the full path and filename of the debug log file. */ boost::filesystem::path getDebugLogFile () const; - // LEGACY FIELDS, REMOVE ASAP + // DEPRECATED boost::filesystem::path CONFIG_FILE; // used by UniqueNodeList private: boost::filesystem::path CONFIG_DIR; boost::filesystem::path DEBUG_LOGFILE; + + void load (); public: - // VFALCO TODO Make this private and fix callers to go through getDatabaseDir() - boost::filesystem::path DATA_DIR; //-------------------------------------------------------------------------- @@ -152,10 +149,6 @@ public: /** List of Validators entries from rippled.cfg */ std::vector validators; -private: - /** The folder where new module databases should be located */ - beast::File m_moduleDbPath; - public: //-------------------------------------------------------------------------- /** Returns the location were databases should be located @@ -164,7 +157,7 @@ public: stored in a file named after the module (e.g. "peerfinder.sqlite") that is inside that directory. */ - beast::File const& getModuleDatabasePath (); + beast::File getModuleDatabasePath () const; //-------------------------------------------------------------------------- @@ -234,9 +227,6 @@ public: std::string START_LEDGER; - // Database - std::string DATABASE_PATH; - // Network parameters int TRANSACTION_FEE_BASE; // The number of fee units a reference transaction costs @@ -312,10 +302,16 @@ public: int getSize (SizedItemName) const; void setup (std::string const& strConf, bool bQuiet); - void load (); + + /** + * Load the conig from the contents of the sting. + * + * @param fileContents String representing the config contents. + */ + void loadFromString (std::string const& fileContents); }; -// VFALCO DEPRECATED +// DEPRECATED extern Config& getConfig(); } // ripple diff --git a/src/ripple/core/ConfigSections.h b/src/ripple/core/ConfigSections.h index 1d6b7e18a3..7c2d42b780 100644 --- a/src/ripple/core/ConfigSections.h +++ b/src/ripple/core/ConfigSections.h @@ -34,7 +34,6 @@ struct ConfigSection #define SECTION_ACCOUNT_PROBE_MAX "account_probe_max" #define SECTION_AMENDMENTS "amendments" #define SECTION_CLUSTER_NODES "cluster_nodes" -#define SECTION_DATABASE_PATH "database_path" #define SECTION_DEBUG_LOGFILE "debug_logfile" #define SECTION_ELB_SUPPORT "elb_support" #define SECTION_FEE_DEFAULT "fee_default" diff --git a/src/ripple/core/impl/Config.cpp b/src/ripple/core/impl/Config.cpp index 45ad36514f..69c53ea547 100644 --- a/src/ripple/core/impl/Config.cpp +++ b/src/ripple/core/impl/Config.cpp @@ -284,6 +284,7 @@ getEnvVar (char const* name) void Config::setup (std::string const& strConf, bool bQuiet) { + boost::filesystem::path dataDir; boost::system::error_code ec; std::string strDbPath, strConfFile; @@ -309,13 +310,13 @@ void Config::setup (std::string const& strConf, bool bQuiet) CONFIG_FILE = strConfFile; CONFIG_DIR = boost::filesystem::absolute (CONFIG_FILE); CONFIG_DIR.remove_filename (); - DATA_DIR = CONFIG_DIR / strDbPath; + dataDir = CONFIG_DIR / strDbPath; } else { CONFIG_DIR = boost::filesystem::current_path (); CONFIG_FILE = CONFIG_DIR / strConfFile; - DATA_DIR = CONFIG_DIR / strDbPath; + dataDir = CONFIG_DIR / strDbPath; // Construct XDG config and data home. // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html @@ -345,7 +346,7 @@ void Config::setup (std::string const& strConf, bool bQuiet) CONFIG_DIR = strXdgConfigHome + "/" + systemName (); CONFIG_FILE = CONFIG_DIR / strConfFile; - DATA_DIR = strXdgDataHome + "/" + systemName (); + dataDir = strXdgDataHome + "/" + systemName (); boost::filesystem::create_directories (CONFIG_DIR, ec); @@ -358,274 +359,257 @@ void Config::setup (std::string const& strConf, bool bQuiet) // Update default values load (); + { + // load() may have set a new value for the dataDir + std::string const dbPath (legacy ("database_path")); + if (!dbPath.empty ()) + { + dataDir = boost::filesystem::path (dbPath); + } + } - boost::filesystem::create_directories (DATA_DIR, ec); + boost::filesystem::create_directories (dataDir, ec); if (ec) - throw std::runtime_error (boost::str (boost::format ("Can not create %s") % DATA_DIR)); + throw std::runtime_error ( + boost::str (boost::format ("Can not create %s") % dataDir)); - // Create the new unified database - m_moduleDbPath = getDatabaseDir(); - - // This code is temporarily disabled, and modules will fall back to using - // per-module databases (e.g. "peerfinder.sqlite") under the module db path - // - //if (m_moduleDbPath.isDirectory ()) - // m_moduleDbPath = m_moduleDbPath.getChildFile("rippled.sqlite"); + legacy ("database_path", boost::filesystem::absolute (dataDir).string ()); } void Config::load () { if (!QUIET) - std::cerr << "Loading: " << CONFIG_FILE << std::endl; + std::cerr << "Loading: " << CONFIG_FILE << "\n"; - std::ifstream ifsConfig (CONFIG_FILE.c_str (), std::ios::in); + std::ifstream ifsConfig (CONFIG_FILE.c_str (), std::ios::in); if (!ifsConfig) { std::cerr << "Failed to open '" << CONFIG_FILE << "'." << std::endl; + return; } - else - { - std::string file_contents; - file_contents.assign ((std::istreambuf_iterator (ifsConfig)), - std::istreambuf_iterator ()); - if (ifsConfig.bad ()) + std::string fileContents; + fileContents.assign ((std::istreambuf_iterator(ifsConfig)), + std::istreambuf_iterator()); + + if (ifsConfig.bad ()) + { + std::cerr << "Failed to read '" << CONFIG_FILE << "'." << std::endl; + return; + } + + loadFromString (fileContents); +} + +void Config::loadFromString (std::string const& fileContents) +{ + IniFileSections secConfig = parseIniFile (fileContents, true); + + build (secConfig); + + if (auto s = getIniFileSection (secConfig, SECTION_VALIDATORS)) + validators = *s; + + if (auto s = getIniFileSection (secConfig, SECTION_CLUSTER_NODES)) + CLUSTER_NODES = *s; + + if (auto s = getIniFileSection (secConfig, SECTION_IPS)) + IPS = *s; + + if (auto s = getIniFileSection (secConfig, SECTION_IPS_FIXED)) + IPS_FIXED = *s; + + if (auto s = getIniFileSection (secConfig, SECTION_SNTP)) + SNTP_SERVERS = *s; + + if (auto s = getIniFileSection (secConfig, SECTION_RPC_STARTUP)) + { + RPC_STARTUP = Json::arrayValue; + + for (auto const& strJson : *s) { - std::cerr << "Failed to read '" << CONFIG_FILE << "'." << std::endl; + Json::Reader jrReader; + Json::Value jvCommand; + + if (!jrReader.parse (strJson, jvCommand)) + throw std::runtime_error ( + boost::str (boost::format ( + "Couldn't parse [" SECTION_RPC_STARTUP "] command: %s") % strJson)); + + RPC_STARTUP.append (jvCommand); } + } + + { + std::string dbPath; + if (getSingleSection (secConfig, "database_path", dbPath)) + { + boost::filesystem::path p(dbPath); + legacy("database_path", + boost::filesystem::absolute (p).string ()); + } + } + + (void) getSingleSection (secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE); + + std::string strTemp; + if (getSingleSection (secConfig, SECTION_PEER_PRIVATE, strTemp)) + PEER_PRIVATE = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_PEERS_MAX, strTemp)) + PEERS_MAX = beast::lexicalCastThrow (strTemp); + + if (auto s = getIniFileSection (secConfig, SECTION_RPC_ADMIN_ALLOW)) + { + std::vector parsedAddresses; + parseAddresses (parsedAddresses, (*s).cbegin(), (*s).cend()); + RPC_ADMIN_ALLOW.insert (RPC_ADMIN_ALLOW.end(), + parsedAddresses.cbegin (), parsedAddresses.cend ()); + } + + insightSettings = parseKeyValueSection (secConfig, SECTION_INSIGHT); + + nodeDatabase = parseKeyValueSection ( + secConfig, ConfigSection::nodeDatabase ()); + + ephemeralNodeDatabase = parseKeyValueSection ( + secConfig, ConfigSection::tempNodeDatabase ()); + + importNodeDatabase = parseKeyValueSection ( + secConfig, ConfigSection::importNodeDatabase ()); + + if (getSingleSection (secConfig, SECTION_NODE_SIZE, strTemp)) + { + if (strTemp == "tiny") + NODE_SIZE = 0; + else if (strTemp == "small") + NODE_SIZE = 1; + else if (strTemp == "medium") + NODE_SIZE = 2; + else if (strTemp == "large") + NODE_SIZE = 3; + else if (strTemp == "huge") + NODE_SIZE = 4; else { - IniFileSections secConfig = parseIniFile (file_contents, true); - std::string strTemp; + NODE_SIZE = beast::lexicalCastThrow (strTemp); - build (secConfig); - - // XXX Leak - IniFileSections::mapped_type* smtTmp; - - smtTmp = getIniFileSection (secConfig, SECTION_VALIDATORS); - - if (smtTmp) - { - validators = *smtTmp; - } - - smtTmp = getIniFileSection (secConfig, SECTION_CLUSTER_NODES); - - if (smtTmp) - { - CLUSTER_NODES = *smtTmp; - } - - smtTmp = getIniFileSection (secConfig, SECTION_IPS); - - if (smtTmp) - { - IPS = *smtTmp; - } - - smtTmp = getIniFileSection (secConfig, SECTION_IPS_FIXED); - - if (smtTmp) - { - IPS_FIXED = *smtTmp; - } - - smtTmp = getIniFileSection (secConfig, SECTION_SNTP); - - if (smtTmp) - { - SNTP_SERVERS = *smtTmp; - } - - smtTmp = getIniFileSection (secConfig, SECTION_RPC_STARTUP); - - if (smtTmp) - { - RPC_STARTUP = Json::arrayValue; - - for (auto const& strJson : *smtTmp) - { - Json::Reader jrReader; - Json::Value jvCommand; - - if (!jrReader.parse (strJson, jvCommand)) - throw std::runtime_error ( - boost::str (boost::format ( - "Couldn't parse [" SECTION_RPC_STARTUP "] command: %s") % strJson)); - - RPC_STARTUP.append (jvCommand); - } - } - - if (getSingleSection (secConfig, SECTION_DATABASE_PATH, DATABASE_PATH)) - DATA_DIR = DATABASE_PATH; - - (void) getSingleSection (secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE); - - if (getSingleSection (secConfig, SECTION_PEER_PRIVATE, strTemp)) - PEER_PRIVATE = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_PEERS_MAX, strTemp)) - PEERS_MAX = beast::lexicalCastThrow (strTemp); - - smtTmp = getIniFileSection (secConfig, SECTION_RPC_ADMIN_ALLOW); - - if (smtTmp) - { - std::vector parsedAddresses; - //parseAddresses, std::vector::const_iterator> - // (parsedAddresses, (*smtTmp).cbegin(), (*smtTmp).cend()); - parseAddresses (parsedAddresses, (*smtTmp).cbegin(), (*smtTmp).cend()); - RPC_ADMIN_ALLOW.insert (RPC_ADMIN_ALLOW.end(), - parsedAddresses.cbegin (), parsedAddresses.cend ()); - } - - insightSettings = parseKeyValueSection (secConfig, SECTION_INSIGHT); - - nodeDatabase = parseKeyValueSection ( - secConfig, ConfigSection::nodeDatabase ()); - - ephemeralNodeDatabase = parseKeyValueSection ( - secConfig, ConfigSection::tempNodeDatabase ()); - - importNodeDatabase = parseKeyValueSection ( - secConfig, ConfigSection::importNodeDatabase ()); - - if (getSingleSection (secConfig, SECTION_NODE_SIZE, strTemp)) - { - if (strTemp == "tiny") - NODE_SIZE = 0; - else if (strTemp == "small") - NODE_SIZE = 1; - else if (strTemp == "medium") - NODE_SIZE = 2; - else if (strTemp == "large") - NODE_SIZE = 3; - else if (strTemp == "huge") - NODE_SIZE = 4; - else - { - NODE_SIZE = beast::lexicalCastThrow (strTemp); - - if (NODE_SIZE < 0) - NODE_SIZE = 0; - else if (NODE_SIZE > 4) - NODE_SIZE = 4; - } - } - - if (getSingleSection (secConfig, SECTION_ELB_SUPPORT, strTemp)) - ELB_SUPPORT = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_WEBSOCKET_PING_FREQ, strTemp)) - WEBSOCKET_PING_FREQ = beast::lexicalCastThrow (strTemp); - - getSingleSection (secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE); - getSingleSection (secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR); - - if (getSingleSection (secConfig, SECTION_SSL_VERIFY, strTemp)) - SSL_VERIFY = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_VALIDATION_SEED, strTemp)) - { - VALIDATION_SEED.setSeedGeneric (strTemp); - - if (VALIDATION_SEED.isValid ()) - { - VALIDATION_PUB = RippleAddress::createNodePublic (VALIDATION_SEED); - VALIDATION_PRIV = RippleAddress::createNodePrivate (VALIDATION_SEED); - } - } - - if (getSingleSection (secConfig, SECTION_NODE_SEED, strTemp)) - { - NODE_SEED.setSeedGeneric (strTemp); - - if (NODE_SEED.isValid ()) - { - NODE_PUB = RippleAddress::createNodePublic (NODE_SEED); - NODE_PRIV = RippleAddress::createNodePrivate (NODE_SEED); - } - } - - if (getSingleSection (secConfig, SECTION_NETWORK_QUORUM, strTemp)) - NETWORK_QUORUM = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_VALIDATION_QUORUM, strTemp)) - VALIDATION_QUORUM = std::max (0, beast::lexicalCastThrow (strTemp)); - - if (getSingleSection (secConfig, SECTION_FEE_ACCOUNT_RESERVE, strTemp)) - FEE_ACCOUNT_RESERVE = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_FEE_OWNER_RESERVE, strTemp)) - FEE_OWNER_RESERVE = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_FEE_OFFER, strTemp)) - FEE_OFFER = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_FEE_DEFAULT, strTemp)) - FEE_DEFAULT = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_FEE_OPERATION, strTemp)) - FEE_CONTRACT_OPERATION = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_LEDGER_HISTORY, strTemp)) - { - boost::to_lower (strTemp); - - if (strTemp == "full") - LEDGER_HISTORY = 1000000000u; - else if (strTemp == "none") - LEDGER_HISTORY = 0; - else - LEDGER_HISTORY = beast::lexicalCastThrow (strTemp); - } - - if (getSingleSection (secConfig, SECTION_FETCH_DEPTH, strTemp)) - { - boost::to_lower (strTemp); - - if (strTemp == "none") - FETCH_DEPTH = 0; - else if (strTemp == "full") - FETCH_DEPTH = 1000000000u; - else - FETCH_DEPTH = beast::lexicalCastThrow (strTemp); - - if (FETCH_DEPTH < 10) - FETCH_DEPTH = 10; - } - - if (getSingleSection (secConfig, SECTION_PATH_SEARCH_OLD, strTemp)) - PATH_SEARCH_OLD = beast::lexicalCastThrow (strTemp); - if (getSingleSection (secConfig, SECTION_PATH_SEARCH, strTemp)) - PATH_SEARCH = beast::lexicalCastThrow (strTemp); - if (getSingleSection (secConfig, SECTION_PATH_SEARCH_FAST, strTemp)) - PATH_SEARCH_FAST = beast::lexicalCastThrow (strTemp); - if (getSingleSection (secConfig, SECTION_PATH_SEARCH_MAX, strTemp)) - PATH_SEARCH_MAX = beast::lexicalCastThrow (strTemp); - - if (getSingleSection (secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp)) - ACCOUNT_PROBE_MAX = beast::lexicalCastThrow (strTemp); - - (void) getSingleSection (secConfig, SECTION_SMS_FROM, SMS_FROM); - (void) getSingleSection (secConfig, SECTION_SMS_KEY, SMS_KEY); - (void) getSingleSection (secConfig, SECTION_SMS_SECRET, SMS_SECRET); - (void) getSingleSection (secConfig, SECTION_SMS_TO, SMS_TO); - (void) getSingleSection (secConfig, SECTION_SMS_URL, SMS_URL); - - if (getSingleSection (secConfig, SECTION_VALIDATORS_FILE, strTemp)) - { - VALIDATORS_FILE = strTemp; - } - - if (getSingleSection (secConfig, SECTION_DEBUG_LOGFILE, strTemp)) - DEBUG_LOGFILE = strTemp; + if (NODE_SIZE < 0) + NODE_SIZE = 0; + else if (NODE_SIZE > 4) + NODE_SIZE = 4; } } + + if (getSingleSection (secConfig, SECTION_ELB_SUPPORT, strTemp)) + ELB_SUPPORT = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_WEBSOCKET_PING_FREQ, strTemp)) + WEBSOCKET_PING_FREQ = beast::lexicalCastThrow (strTemp); + + getSingleSection (secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE); + getSingleSection (secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR); + + if (getSingleSection (secConfig, SECTION_SSL_VERIFY, strTemp)) + SSL_VERIFY = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_VALIDATION_SEED, strTemp)) + { + VALIDATION_SEED.setSeedGeneric (strTemp); + + if (VALIDATION_SEED.isValid ()) + { + VALIDATION_PUB = RippleAddress::createNodePublic (VALIDATION_SEED); + VALIDATION_PRIV = RippleAddress::createNodePrivate (VALIDATION_SEED); + } + } + + if (getSingleSection (secConfig, SECTION_NODE_SEED, strTemp)) + { + NODE_SEED.setSeedGeneric (strTemp); + + if (NODE_SEED.isValid ()) + { + NODE_PUB = RippleAddress::createNodePublic (NODE_SEED); + NODE_PRIV = RippleAddress::createNodePrivate (NODE_SEED); + } + } + + if (getSingleSection (secConfig, SECTION_NETWORK_QUORUM, strTemp)) + NETWORK_QUORUM = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_VALIDATION_QUORUM, strTemp)) + VALIDATION_QUORUM = std::max (0, beast::lexicalCastThrow (strTemp)); + + if (getSingleSection (secConfig, SECTION_FEE_ACCOUNT_RESERVE, strTemp)) + FEE_ACCOUNT_RESERVE = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_FEE_OWNER_RESERVE, strTemp)) + FEE_OWNER_RESERVE = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_FEE_OFFER, strTemp)) + FEE_OFFER = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_FEE_DEFAULT, strTemp)) + FEE_DEFAULT = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_FEE_OPERATION, strTemp)) + FEE_CONTRACT_OPERATION = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_LEDGER_HISTORY, strTemp)) + { + boost::to_lower (strTemp); + + if (strTemp == "full") + LEDGER_HISTORY = 1000000000u; + else if (strTemp == "none") + LEDGER_HISTORY = 0; + else + LEDGER_HISTORY = beast::lexicalCastThrow (strTemp); + } + + if (getSingleSection (secConfig, SECTION_FETCH_DEPTH, strTemp)) + { + boost::to_lower (strTemp); + + if (strTemp == "none") + FETCH_DEPTH = 0; + else if (strTemp == "full") + FETCH_DEPTH = 1000000000u; + else + FETCH_DEPTH = beast::lexicalCastThrow (strTemp); + + if (FETCH_DEPTH < 10) + FETCH_DEPTH = 10; + } + + if (getSingleSection (secConfig, SECTION_PATH_SEARCH_OLD, strTemp)) + PATH_SEARCH_OLD = beast::lexicalCastThrow (strTemp); + if (getSingleSection (secConfig, SECTION_PATH_SEARCH, strTemp)) + PATH_SEARCH = beast::lexicalCastThrow (strTemp); + if (getSingleSection (secConfig, SECTION_PATH_SEARCH_FAST, strTemp)) + PATH_SEARCH_FAST = beast::lexicalCastThrow (strTemp); + if (getSingleSection (secConfig, SECTION_PATH_SEARCH_MAX, strTemp)) + PATH_SEARCH_MAX = beast::lexicalCastThrow (strTemp); + + if (getSingleSection (secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp)) + ACCOUNT_PROBE_MAX = beast::lexicalCastThrow (strTemp); + + (void) getSingleSection (secConfig, SECTION_SMS_FROM, SMS_FROM); + (void) getSingleSection (secConfig, SECTION_SMS_KEY, SMS_KEY); + (void) getSingleSection (secConfig, SECTION_SMS_SECRET, SMS_SECRET); + (void) getSingleSection (secConfig, SECTION_SMS_TO, SMS_TO); + (void) getSingleSection (secConfig, SECTION_SMS_URL, SMS_URL); + + if (getSingleSection (secConfig, SECTION_VALIDATORS_FILE, strTemp)) + { + VALIDATORS_FILE = strTemp; + } + + if (getSingleSection (secConfig, SECTION_DEBUG_LOGFILE, strTemp)) + DEBUG_LOGFILE = strTemp; } int Config::getSize (SizedItemName item) const @@ -702,19 +686,12 @@ boost::filesystem::path Config::getDebugLogFile () const return log_file; } -//------------------------------------------------------------------------------ -// -// VFALCO NOTE Clean members area -// - Config& getConfig () { static Config config; return config; } -//------------------------------------------------------------------------------ - beast::File Config::getConfigDir () const { beast::String const s (CONFIG_FILE.native().c_str ()); @@ -723,14 +700,6 @@ beast::File Config::getConfigDir () const return beast::File::nonexistent (); } -beast::File Config::getDatabaseDir () const -{ - beast::String const s (DATA_DIR.native().c_str()); - if (s.isNotEmpty ()) - return beast::File (s); - return beast::File::nonexistent (); -} - beast::File Config::getValidatorsFile () const { beast::String const s (VALIDATORS_FILE.native().c_str()); @@ -744,9 +713,14 @@ beast::URL Config::getValidatorsURL () const return beast::parse_URL (VALIDATORS_SITE).second; } -beast::File const& Config::getModuleDatabasePath () +beast::File Config::getModuleDatabasePath () const { - return m_moduleDbPath; + boost::filesystem::path dbPath (legacy ("database_path")); + + beast::String const s (dbPath.native ().c_str ()); + if (s.isNotEmpty ()) + return beast::File (s); + return beast::File::nonexistent (); } } // ripple diff --git a/src/ripple/core/tests/Config.test.cpp b/src/ripple/core/tests/Config.test.cpp new file mode 100644 index 0000000000..573b14f3a4 --- /dev/null +++ b/src/ripple/core/tests/Config.test.cpp @@ -0,0 +1,356 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012-2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { +namespace detail { +std::string configContents (std::string const& dbPath) +{ + static boost::format configContentsTemplate (R"rippleConfig( +[server] +port_rpc +port_peer +port_wss_admin + +[port_rpc] +port = 5005 +ip = 127.0.0.1 +admin = allow +protocol = https + +[port_peer] +port = 51235 +ip = 0.0.0.0 +protocol = peer + +[port_wss_admin] +port = 6006 +ip = 127.0.0.1 +admin = allow +protocol = wss + +#[port_ws_public] +#port = 5005 +#ip = 127.0.0.1 +#protocol = wss + +#------------------------------------------------------------------------------- + +[node_size] +medium + +# This is primary persistent datastore for rippled. This includes transaction +# metadata, account states, and ledger headers. Helpful information can be +# found here: https://ripple.com/wiki/NodeBackEnd +# delete old ledgers while maintaining at least 2000. Do not require an +# external administrative command to initiate deletion. +[node_db] +type=memory +path=/Users/dummy/ripple/config/db/rocksdb +open_files=2000 +filter_bits=12 +cache_mb=256 +file_size_mb=8 +file_size_mult=2 + +%1% +%2% + +# This needs to be an absolute directory reference, not a relative one. +# Modify this value as required. +[debug_logfile] +/Users/dummy/ripple/config/log/debug.log + +[sntp_servers] +time.windows.com +time.apple.com +time.nist.gov +pool.ntp.org + +# Where to find some other servers speaking the Ripple protocol. +# +[ips] +r.ripple.com 51235 + +# The latest validators can be obtained from +# https://ripple.com/ripple.txt +# +[validators] +n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1 +n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2 +n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3 +n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4 +n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5 + +# Ditto. +[validation_quorum] +3 + +# Turn down default logging to save disk space in the long run. +# Valid values here are trace, debug, info, warning, error, and fatal +[rpc_startup] +{ "command": "log_level", "severity": "warning" } + +# Defaults to 1 ("yes") so that certificates will be validated. To allow the use +# of self-signed certificates for development or internal use, set to 0 ("no"). +[ssl_verify] +0 + +[sqdb] +backend=sqlite +)rippleConfig"); + + if (!dbPath.empty ()) + return boost::str (configContentsTemplate % "[database_path]" % dbPath); + else + return boost::str (configContentsTemplate % "" % ""); +} + +/** + Write a config file and remove when done. + */ +class ConfigGuard +{ +private: + using path = boost::filesystem::path; + path subDir_; + path configFile_; + path dataDir_; + + bool rmSubDir_{false}; + bool rmDataDir_{false}; + + Config config_; + +public: + ConfigGuard (std::string subDir, std::string const& dbPath) + : subDir_ (std::move (subDir)), dataDir_ (dbPath) + { + using namespace boost::filesystem; + + if (dbPath.empty ()) + { + dataDir_ = subDir_ / path (Config::Helpers::getDatabaseDirName ()); + } + + configFile_ = subDir_ / path (Config::Helpers::getConfigFileName ()); + { + if (!exists (subDir_)) + { + create_directory (subDir_); + rmSubDir_ = true; + } + else if (is_directory (subDir_)) + rmSubDir_ = false; + else + { + // Cannot run the test someone created a file where we want to + // put out directory + throw std::runtime_error ("Cannot create directory: " + + subDir_.string ()); + } + } + + if (!exists (configFile_)) + { + std::ofstream o (configFile_.string ()); + o << configContents (dbPath); + } + else + { + throw std::runtime_error ( + "Refusing to overwrite existing config file: " + + configFile_.string ()); + } + + rmDataDir_ = !exists (dataDir_); + config_.setup (configFile_.string (), /*bQuiet*/ false); + } + Config& config () + { + return config_; + } + bool dataDirExists () const + { + return boost::filesystem::is_directory (dataDir_); + } + bool configFileExists () const + { + return boost::filesystem::is_regular_file (configFile_); + } + ~ConfigGuard () + { + try + { + using namespace boost::filesystem; + if (!is_regular_file (configFile_)) + std::cerr << "Expected " << configFile_.string () + << " to be an existing file.\n"; + else + remove (configFile_.string ()); + + auto rmDir = [](path const& toRm) + { + if (is_directory (toRm) && is_empty (toRm)) + remove (toRm); + else + std::cerr << "Expected " << toRm.string () + << " to be an empty existing directory.\n"; + }; + + if (rmDataDir_) + rmDir (dataDir_); + else + std::cerr << "Skipping rm dir: " << dataDir_.string () << "\n"; + + if (rmSubDir_) + rmDir (subDir_); + else + std::cerr << "Skipping rm dir: " << subDir_.string () << "\n"; + } + catch (std::exception& e) + { + // if we throw here, just let it die. + std::cerr << "Error in CreateConfigGuard: " << e.what () << "\n"; + }; + } +}; +} // detail +class Config_test final : public TestSuite +{ +private: + using path = boost::filesystem::path; + +public: + void testLegacy () + { + testcase ("legacy"); + + Config c; + + std::string toLoad(R"rippleConfig( +[server] +port_rpc +port_peer +port_wss_admin + +[ssl_verify] +0 + +[validation_quorum] +3 +)rippleConfig"); + + c.loadFromString (toLoad); + + expect (c.legacy ("ssl_verify") == "0"); + expectException ([&c] {c.legacy ("server");}); // not a single line + + // set a legacy value + expect (c.legacy ("not_in_file") == ""); + c.legacy ("not_in_file", "new_value"); + expect (c.legacy ("not_in_file") == "new_value"); + } + void testDbPath () + { + testcase ("database_path"); + + using namespace boost::filesystem; + { + boost::format cc ("[database_path]\n%1%\n"); + + auto const cwd = current_path (); + path const dataDirRel ("test_data_dir"); + path const dataDirAbs (cwd / dataDirRel); + { + // Dummy test - do we get back what we put in + Config c; + c.loadFromString (boost::str (cc % dataDirAbs.string ())); + expect (c.legacy ("database_path") == dataDirAbs.string ()); + } + { + // Rel paths should convert to abs paths + Config c; + c.loadFromString (boost::str (cc % dataDirRel.string ())); + expect (c.legacy ("database_path") == dataDirAbs.string ()); + } + { + // No db sectcion. + // N.B. Config::setup will give database_path a default, + // load will not. + Config c; + c.loadFromString (""); + expect (c.legacy ("database_path") == ""); + } + } + { + // read from file absolute path + auto const cwd = current_path (); + path const dataDirRel ("test_data_dir"); + path const dataDirAbs (cwd / path ("test_db") / dataDirRel); + detail::ConfigGuard g ("test_db", dataDirAbs.string ()); + auto& c (g.config ()); + expect (g.dataDirExists ()); + expect (g.configFileExists ()); + expect (c.legacy ("database_path") == dataDirAbs.string (), + "dbPath Abs Path File"); + } + { + // read from file relative path + std::string const dbPath ("my_db"); + detail::ConfigGuard g ("test_db", dbPath); + auto& c (g.config ()); + std::string const nativeDbPath = absolute (path (dbPath)).string (); + expect (g.dataDirExists ()); + expect (g.configFileExists ()); + expect (c.legacy ("database_path") == nativeDbPath, + "dbPath Rel Path File"); + } + { + // read from file no path + detail::ConfigGuard g ("test_db", ""); + auto& c (g.config ()); + std::string const nativeDbPath = + absolute (path ("test_db") / + path (Config::Helpers::getDatabaseDirName ())) + .string (); + expect (g.dataDirExists ()); + expect (g.configFileExists ()); + expect (c.legacy ("database_path") == nativeDbPath, + "dbPath No Path"); + } + } + void run () + { + testLegacy (); + testDbPath (); + } +}; + +BEAST_DEFINE_TESTSUITE (Config, core, ripple); + +} // ripple diff --git a/src/ripple/unity/core.cpp b/src/ripple/unity/core.cpp index 010adda39e..033e90b08a 100644 --- a/src/ripple/unity/core.cpp +++ b/src/ripple/unity/core.cpp @@ -27,3 +27,4 @@ #include #include +#include