mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Dynamize trusted validator list and quorum (RIPD-1220):
Instead of specifying a static list of trusted validators in the config or validators file, the configuration can now include trusted validator list publisher keys. The trusted validator list and quorum are now reset each consensus round using the latest validator lists and the list of recent validations seen. The minimum validation quorum is now only configurable via the command line.
This commit is contained in:
@@ -138,8 +138,6 @@ public:
|
||||
|
||||
// Note: The following parameters do not relate to the UNL or trust at all
|
||||
std::size_t NETWORK_QUORUM = 0; // Minimum number of nodes to consider the network present
|
||||
int VALIDATION_QUORUM = 1; // Minimum validations to consider ledger authoritative
|
||||
bool LOCK_QUORUM = false; // Do not raise the quorum
|
||||
|
||||
// Peer networking parameters
|
||||
bool PEER_PRIVATE = false; // True to ask peers not to relay current IP.
|
||||
@@ -156,6 +154,7 @@ public:
|
||||
// Validation
|
||||
PublicKey VALIDATION_PUB;
|
||||
SecretKey VALIDATION_PRIV;
|
||||
boost::optional<std::size_t> VALIDATION_QUORUM; // Minimum validations to consider ledger authoritative
|
||||
|
||||
// Node Identity
|
||||
std::string NODE_SEED;
|
||||
|
||||
@@ -60,11 +60,11 @@ struct ConfigSection
|
||||
#define SECTION_SSL_VERIFY_FILE "ssl_verify_file"
|
||||
#define SECTION_SSL_VERIFY_DIR "ssl_verify_dir"
|
||||
#define SECTION_VALIDATORS_FILE "validators_file"
|
||||
#define SECTION_VALIDATION_QUORUM "validation_quorum"
|
||||
#define SECTION_VALIDATION_SEED "validation_seed"
|
||||
#define SECTION_WEBSOCKET_PING_FREQ "websocket_ping_frequency"
|
||||
#define SECTION_VALIDATORS "validators"
|
||||
#define SECTION_VALIDATOR_KEYS "validator_keys"
|
||||
#define SECTION_VALIDATOR_LIST_KEYS "validator_list_keys"
|
||||
#define SECTION_VALIDATORS "validators"
|
||||
#define SECTION_VALIDATION_MANIFEST "validation_manifest"
|
||||
#define SECTION_VETO_AMENDMENTS "veto_amendments"
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ enum JobType
|
||||
jtUPDATE_PF, // Update pathfinding requests
|
||||
jtTRANSACTION, // A transaction received from the network
|
||||
jtBATCH, // Apply batched transactions
|
||||
jtUNL, // A Score or Fetch of the UNL (DEPRECATED)
|
||||
jtADVANCE, // Advance validated/acquired ledgers
|
||||
jtPUBLEDGER, // Publish a fully-accepted ledger
|
||||
jtTXN_DATA, // Fetch a proposed set
|
||||
|
||||
@@ -50,7 +50,6 @@ add( jtRPC, "RPC", maxLimit, false, 0, 0);
|
||||
add( jtUPDATE_PF, "updatePaths", maxLimit, false, 0, 0);
|
||||
add( jtTRANSACTION, "transaction", maxLimit, false, 250, 1000);
|
||||
add( jtBATCH, "batch", maxLimit, false, 250, 1000);
|
||||
add( jtUNL, "unl", 1, false, 0, 0);
|
||||
add( jtADVANCE, "advanceLedger", maxLimit, false, 0, 0);
|
||||
add( jtPUBLEDGER, "publishNewLedger", maxLimit, false, 3000, 4500);
|
||||
add( jtTXN_DATA, "fetchTxnData", 1, false, 0, 0);
|
||||
|
||||
@@ -318,7 +318,7 @@ void Config::loadFromString (std::string const& fileContents)
|
||||
std::string strTemp;
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_PEER_PRIVATE, strTemp, j_))
|
||||
PEER_PRIVATE = beast::lexicalCastThrow <bool> (strTemp);
|
||||
PEER_PRIVATE = beast::lexicalCastThrow <bool> (strTemp);
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_PEERS_MAX, strTemp, j_))
|
||||
PEERS_MAX = std::max (0, beast::lexicalCastThrow <int> (strTemp));
|
||||
@@ -378,9 +378,6 @@ void Config::loadFromString (std::string const& fileContents)
|
||||
if (getSingleSection (secConfig, SECTION_NETWORK_QUORUM, strTemp, j_))
|
||||
NETWORK_QUORUM = beast::lexicalCastThrow <std::size_t> (strTemp);
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_VALIDATION_QUORUM, strTemp, j_))
|
||||
VALIDATION_QUORUM = std::max (0, beast::lexicalCastThrow <int> (strTemp));
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_FEE_ACCOUNT_RESERVE, strTemp, j_))
|
||||
FEE_ACCOUNT_RESERVE = beast::lexicalCastThrow <std::uint64_t> (strTemp);
|
||||
|
||||
@@ -425,107 +422,109 @@ void Config::loadFromString (std::string const& fileContents)
|
||||
if (getSingleSection (secConfig, SECTION_PATH_SEARCH_MAX, strTemp, j_))
|
||||
PATH_SEARCH_MAX = beast::lexicalCastThrow <int> (strTemp);
|
||||
|
||||
// If a file was explicitly specified, then throw if the
|
||||
// path is malformed or if the file does not exist or is
|
||||
// not a file.
|
||||
// If the specified file is not an absolute path, then look
|
||||
// for it in the same directory as the config file.
|
||||
// If no path was specified, then look for validators.txt
|
||||
// in the same directory as the config file, but don't complain
|
||||
// if we can't find it.
|
||||
boost::filesystem::path validatorsFile;
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_VALIDATORS_FILE, strTemp, j_))
|
||||
{
|
||||
validatorsFile = strTemp;
|
||||
|
||||
if (validatorsFile.empty ())
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid path specified in [" SECTION_VALIDATORS_FILE "]");
|
||||
|
||||
if (!validatorsFile.is_absolute() && !CONFIG_DIR.empty())
|
||||
validatorsFile = CONFIG_DIR / validatorsFile;
|
||||
|
||||
if (!boost::filesystem::exists (validatorsFile))
|
||||
Throw<std::runtime_error> (
|
||||
"The file specified in [" SECTION_VALIDATORS_FILE "] "
|
||||
"does not exist: " + validatorsFile.string());
|
||||
|
||||
else if (!boost::filesystem::is_regular_file (validatorsFile) &&
|
||||
!boost::filesystem::is_symlink (validatorsFile))
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid file specified in [" SECTION_VALIDATORS_FILE "]: " +
|
||||
validatorsFile.string());
|
||||
}
|
||||
else if (!CONFIG_DIR.empty())
|
||||
{
|
||||
validatorsFile = CONFIG_DIR / validatorsFileName;
|
||||
|
||||
if (!validatorsFile.empty ())
|
||||
{
|
||||
if(!boost::filesystem::exists (validatorsFile))
|
||||
validatorsFile.clear();
|
||||
else if (!boost::filesystem::is_regular_file (validatorsFile) &&
|
||||
!boost::filesystem::is_symlink (validatorsFile))
|
||||
validatorsFile.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!validatorsFile.empty () &&
|
||||
boost::filesystem::exists (validatorsFile) &&
|
||||
(boost::filesystem::is_regular_file (validatorsFile) ||
|
||||
boost::filesystem::is_symlink (validatorsFile)))
|
||||
{
|
||||
std::ifstream ifsDefault (validatorsFile.native().c_str());
|
||||
|
||||
std::string data;
|
||||
|
||||
data.assign (
|
||||
std::istreambuf_iterator<char>(ifsDefault),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
auto iniFile = parseIniFile (data, true);
|
||||
|
||||
auto entries = getIniFileSection (
|
||||
iniFile,
|
||||
SECTION_VALIDATORS);
|
||||
|
||||
if (entries)
|
||||
section (SECTION_VALIDATORS).append (*entries);
|
||||
|
||||
auto valKeyEntries = getIniFileSection(
|
||||
iniFile,
|
||||
SECTION_VALIDATOR_KEYS);
|
||||
|
||||
if (valKeyEntries)
|
||||
section (SECTION_VALIDATOR_KEYS).append (*valKeyEntries);
|
||||
|
||||
if (!entries && !valKeyEntries)
|
||||
Throw<std::runtime_error> (
|
||||
"The file specified in [" SECTION_VALIDATORS_FILE "] "
|
||||
"does not contain a [" SECTION_VALIDATORS "] or "
|
||||
"[" SECTION_VALIDATOR_KEYS "] section: " +
|
||||
validatorsFile.string());
|
||||
|
||||
// Look for [validation_quorum] in the validators file
|
||||
// if it was not in the config
|
||||
if (!getIniFileSection (secConfig, SECTION_VALIDATION_QUORUM))
|
||||
{
|
||||
if (!getSingleSection (
|
||||
iniFile, SECTION_VALIDATION_QUORUM, strTemp, j_))
|
||||
Throw<std::runtime_error> (
|
||||
"The file specified in [" SECTION_VALIDATORS_FILE "] "
|
||||
"does not contain a [" SECTION_VALIDATION_QUORUM "] "
|
||||
"section: " + validatorsFile.string());
|
||||
else
|
||||
VALIDATION_QUORUM = std::max (
|
||||
0, beast::lexicalCastThrow <int> (strTemp));
|
||||
}
|
||||
}
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_DEBUG_LOGFILE, strTemp, j_))
|
||||
DEBUG_LOGFILE = strTemp;
|
||||
|
||||
// Do not load trusted validator configuration for standalone mode
|
||||
if (! RUN_STANDALONE)
|
||||
{
|
||||
// If a file was explicitly specified, then throw if the
|
||||
// path is malformed or if the file does not exist or is
|
||||
// not a file.
|
||||
// If the specified file is not an absolute path, then look
|
||||
// for it in the same directory as the config file.
|
||||
// If no path was specified, then look for validators.txt
|
||||
// in the same directory as the config file, but don't complain
|
||||
// if we can't find it.
|
||||
boost::filesystem::path validatorsFile;
|
||||
|
||||
if (getSingleSection (secConfig, SECTION_VALIDATORS_FILE, strTemp, j_))
|
||||
{
|
||||
validatorsFile = strTemp;
|
||||
|
||||
if (validatorsFile.empty ())
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid path specified in [" SECTION_VALIDATORS_FILE "]");
|
||||
|
||||
if (!validatorsFile.is_absolute() && !CONFIG_DIR.empty())
|
||||
validatorsFile = CONFIG_DIR / validatorsFile;
|
||||
|
||||
if (!boost::filesystem::exists (validatorsFile))
|
||||
Throw<std::runtime_error> (
|
||||
"The file specified in [" SECTION_VALIDATORS_FILE "] "
|
||||
"does not exist: " + validatorsFile.string());
|
||||
|
||||
else if (!boost::filesystem::is_regular_file (validatorsFile) &&
|
||||
!boost::filesystem::is_symlink (validatorsFile))
|
||||
Throw<std::runtime_error> (
|
||||
"Invalid file specified in [" SECTION_VALIDATORS_FILE "]: " +
|
||||
validatorsFile.string());
|
||||
}
|
||||
else if (!CONFIG_DIR.empty())
|
||||
{
|
||||
validatorsFile = CONFIG_DIR / validatorsFileName;
|
||||
|
||||
if (!validatorsFile.empty ())
|
||||
{
|
||||
if(!boost::filesystem::exists (validatorsFile))
|
||||
validatorsFile.clear();
|
||||
else if (!boost::filesystem::is_regular_file (validatorsFile) &&
|
||||
!boost::filesystem::is_symlink (validatorsFile))
|
||||
validatorsFile.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!validatorsFile.empty () &&
|
||||
boost::filesystem::exists (validatorsFile) &&
|
||||
(boost::filesystem::is_regular_file (validatorsFile) ||
|
||||
boost::filesystem::is_symlink (validatorsFile)))
|
||||
{
|
||||
std::ifstream ifsDefault (validatorsFile.native().c_str());
|
||||
|
||||
std::string data;
|
||||
|
||||
data.assign (
|
||||
std::istreambuf_iterator<char>(ifsDefault),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
auto iniFile = parseIniFile (data, true);
|
||||
|
||||
auto entries = getIniFileSection (
|
||||
iniFile,
|
||||
SECTION_VALIDATORS);
|
||||
|
||||
if (entries)
|
||||
section (SECTION_VALIDATORS).append (*entries);
|
||||
|
||||
auto valKeyEntries = getIniFileSection(
|
||||
iniFile,
|
||||
SECTION_VALIDATOR_KEYS);
|
||||
|
||||
if (valKeyEntries)
|
||||
section (SECTION_VALIDATOR_KEYS).append (*valKeyEntries);
|
||||
|
||||
auto valListKeys = getIniFileSection(
|
||||
iniFile,
|
||||
SECTION_VALIDATOR_LIST_KEYS);
|
||||
|
||||
if (valListKeys)
|
||||
section (SECTION_VALIDATOR_LIST_KEYS).append (*valListKeys);
|
||||
|
||||
if (!entries && !valKeyEntries && !valListKeys)
|
||||
Throw<std::runtime_error> (
|
||||
"The file specified in [" SECTION_VALIDATORS_FILE "] "
|
||||
"does not contain a [" SECTION_VALIDATORS "], "
|
||||
"[" SECTION_VALIDATOR_KEYS "] or "
|
||||
"[" SECTION_VALIDATOR_LIST_KEYS "]"
|
||||
" section: " +
|
||||
validatorsFile.string());
|
||||
}
|
||||
|
||||
// Consolidate [validator_keys] and [validators]
|
||||
section (SECTION_VALIDATORS).append (
|
||||
section (SECTION_VALIDATOR_KEYS).lines ());
|
||||
}
|
||||
|
||||
{
|
||||
auto const part = section("features");
|
||||
for(auto const& s : part.values())
|
||||
|
||||
Reference in New Issue
Block a user