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:
wilsonianb
2016-08-30 09:46:24 -07:00
committed by seelabs
parent 74977ab3db
commit e823e60ca0
42 changed files with 2482 additions and 1570 deletions

View File

@@ -285,9 +285,9 @@ public:
}
};
std::string valFileContents (boost::optional<int> const& quorum)
std::string valFileContents ()
{
static boost::format configContentsTemplate (R"rippleConfig(
std::string configContents (R"rippleConfig(
[validators]
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
@@ -300,14 +300,11 @@ nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
nHUPDdcdb2Y5DZAJne4c2iabFuAP3F34xZUgYQT2NH7qfkdapgnz
%1%
[validator_list_keys]
03E74EE14CB525AFBB9F1B7D86CD58ECC4B91452294B42AB4E78F260BD905C091D
030775A669685BD6ABCEBD80385921C7851783D991A8055FD21D2F3966C96F1B56
)rippleConfig");
std::string quorumSection =
quorum ? "[validation_quorum]\n" + to_string(*quorum) : "";
return boost::str (
configContentsTemplate % quorumSection);
return configContents;
}
/**
@@ -321,7 +318,7 @@ private:
public:
ValidatorsTxtGuard (beast::unit_test::suite& test,
path subDir, path const& validatorsFileName,
boost::optional<int> const& quorum, bool useCounter = true)
bool useCounter = true)
: ConfigGuard (test, std::move (subDir), useCounter)
{
using namespace boost::filesystem;
@@ -332,7 +329,7 @@ public:
if (!exists (validatorsFile_))
{
std::ofstream o (validatorsFile_.string ());
o << valFileContents (quorum);
o << valFileContents ();
}
else
{
@@ -392,9 +389,6 @@ port_wss_admin
[ssl_verify]
0
[validation_quorum]
3
)rippleConfig");
c.loadFromString (toLoad);
@@ -499,9 +493,8 @@ port_wss_admin
}
{
// load should throw for invalid [validators_file]
int const quorum = 3;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.cfg", quorum);
*this, "test_cfg", "validators.cfg");
path const invalidFile = current_path () / vtg.subdir ();
boost::format cc ("[validators_file]\n%1%\n");
std::string error;
@@ -517,7 +510,7 @@ port_wss_admin
BEAST_EXPECT(error == expectedError);
}
{
// load validators and quorum from config
// load validators from config into single section
Config c;
std::string toLoad(R"rippleConfig(
[validators]
@@ -528,53 +521,59 @@ n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
[validator_keys]
nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
[validation_quorum]
4
)rippleConfig");
c.loadFromString (toLoad);
BEAST_EXPECT(c.legacy ("validators_file").empty ());
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 3);
BEAST_EXPECT(c.section (SECTION_VALIDATOR_KEYS).values ().size () == 2);
BEAST_EXPECT(c.VALIDATION_QUORUM == 4);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 5);
}
{
// load validator list keys from config
Config c;
std::string toLoad(R"rippleConfig(
[validator_list_keys]
021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
)rippleConfig");
c.loadFromString (toLoad);
BEAST_EXPECT(
c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 1);
BEAST_EXPECT(
c.section (SECTION_VALIDATOR_LIST_KEYS).values ()[0] ==
"021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566");
}
{
// load from specified [validators_file] absolute path
int const quorum = 3;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.cfg", quorum);
*this, "test_cfg", "validators.cfg");
BEAST_EXPECT(vtg.validatorsFileExists ());
Config c;
boost::format cc ("[validators_file]\n%1%\n");
c.loadFromString (boost::str (cc % vtg.validatorsFile ()));
BEAST_EXPECT(c.legacy ("validators_file") == vtg.validatorsFile ());
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 5);
BEAST_EXPECT(c.section (SECTION_VALIDATOR_KEYS).values ().size () == 3);
BEAST_EXPECT(c.VALIDATION_QUORUM == quorum);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
BEAST_EXPECT(
c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
}
{
// load from specified [validators_file] file name
// in config directory
int const quorum = 3;
std::string const valFileName = "validators.txt";
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", valFileName, quorum);
*this, "test_cfg", valFileName);
detail::RippledCfgGuard const rcg (
*this, vtg.subdir (), "", valFileName, false);
BEAST_EXPECT(vtg.validatorsFileExists ());
BEAST_EXPECT(rcg.configFileExists ());
auto const& c (rcg.config ());
BEAST_EXPECT(c.legacy ("validators_file") == valFileName);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 5);
BEAST_EXPECT(c.section (SECTION_VALIDATOR_KEYS).values ().size () == 3);
BEAST_EXPECT(c.VALIDATION_QUORUM == quorum);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
BEAST_EXPECT(
c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
}
{
// load from specified [validators_file] relative path
// to config directory
int const quorum = 3;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.txt", quorum);
*this, "test_cfg", "validators.txt");
auto const valFilePath = ".." / vtg.subdir() / "validators.txt";
detail::RippledCfgGuard const rcg (
*this, vtg.subdir (), "", valFilePath, false);
@@ -582,63 +581,41 @@ nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
BEAST_EXPECT(rcg.configFileExists ());
auto const& c (rcg.config ());
BEAST_EXPECT(c.legacy ("validators_file") == valFilePath);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 5);
BEAST_EXPECT(c.section (SECTION_VALIDATOR_KEYS).values ().size () == 3);
BEAST_EXPECT(c.VALIDATION_QUORUM == quorum);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
BEAST_EXPECT(
c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
}
{
// load from validators file in default location
int const quorum = 3;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.txt", quorum);
*this, "test_cfg", "validators.txt");
detail::RippledCfgGuard const rcg (*this, vtg.subdir (),
"", "", false);
BEAST_EXPECT(vtg.validatorsFileExists ());
BEAST_EXPECT(rcg.configFileExists ());
auto const& c (rcg.config ());
BEAST_EXPECT(c.legacy ("validators_file").empty ());
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 5);
BEAST_EXPECT(c.section (SECTION_VALIDATOR_KEYS).values ().size () == 3);
BEAST_EXPECT(c.VALIDATION_QUORUM == quorum);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
BEAST_EXPECT(
c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
}
{
// load from specified [validators_file] instead
// of default location
int const quorum = 3;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.cfg", quorum);
*this, "test_cfg", "validators.cfg");
BEAST_EXPECT(vtg.validatorsFileExists ());
detail::ValidatorsTxtGuard const vtgDefault (
*this, vtg.subdir (), "validators.txt", 4, false);
*this, vtg.subdir (), "validators.txt", false);
BEAST_EXPECT(vtgDefault.validatorsFileExists ());
detail::RippledCfgGuard const rcg (
*this, vtg.subdir (), "", vtg.validatorsFile (), false);
BEAST_EXPECT(rcg.configFileExists ());
auto const& c (rcg.config ());
BEAST_EXPECT(c.legacy ("validators_file") == vtg.validatorsFile ());
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 5);
BEAST_EXPECT(c.section (SECTION_VALIDATOR_KEYS).values ().size () == 3);
BEAST_EXPECT(c.VALIDATION_QUORUM == quorum);
}
{
// do not load quorum from validators file if in config
boost::format cc (R"rippleConfig(
[validators_file]
%1%
[validation_quorum]
4
)rippleConfig");
int const quorum = 3;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.cfg", quorum);
BEAST_EXPECT(vtg.validatorsFileExists ());
Config c;
c.loadFromString (boost::str (cc % vtg.validatorsFile ()));
BEAST_EXPECT(c.legacy ("validators_file") == vtg.validatorsFile ());
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 5);
BEAST_EXPECT(c.section (SECTION_VALIDATOR_KEYS).values ().size () == 3);
BEAST_EXPECT(c.VALIDATION_QUORUM == 4);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 8);
BEAST_EXPECT(
c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 2);
}
{
@@ -658,51 +635,34 @@ n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
nHB1X37qrniVugfQcuBTAjswphC1drx7QjFFojJPZwKHHnt8kU7v
nHUkAWDR4cB8AgPg7VXMX6et8xRTQb2KJfgv1aBEXozwrawRKgMB
[validator_list_keys]
021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
)rippleConfig");
int const quorum = 3;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.cfg", quorum);
*this, "test_cfg", "validators.cfg");
BEAST_EXPECT(vtg.validatorsFileExists ());
Config c;
c.loadFromString (boost::str (cc % vtg.validatorsFile ()));
BEAST_EXPECT(c.legacy ("validators_file") == vtg.validatorsFile ());
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 10);
BEAST_EXPECT(c.section (SECTION_VALIDATOR_KEYS).values ().size () == 5);
BEAST_EXPECT(c.VALIDATION_QUORUM == quorum);
BEAST_EXPECT(c.section (SECTION_VALIDATORS).values ().size () == 15);
BEAST_EXPECT(
c.section (SECTION_VALIDATOR_LIST_KEYS).values ().size () == 3);
}
{
// load should throw if [validators] and [validator_keys] are
// missing from rippled cfg and validators file
// load should throw if [validators], [validator_keys] and
// [validator_list_keys] are missing from rippled cfg and
// validators file
Config c;
boost::format cc ("[validators_file]\n%1%\n");
std::string error;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.cfg", boost::none);
*this, "test_cfg", "validators.cfg");
BEAST_EXPECT(vtg.validatorsFileExists ());
auto const expectedError =
"The file specified in [validators_file] does not contain a "
"[validators] or [validator_keys] section: " +
"[validators], [validator_keys] or [validator_list_keys] section: " +
vtg.validatorsFile ();
std::ofstream o (vtg.validatorsFile ());
o << "[validation_quorum]\n3\n";
try {
Config c;
c.loadFromString (boost::str (cc % vtg.validatorsFile ()));
} catch (std::runtime_error& e) {
error = e.what();
}
BEAST_EXPECT(error == expectedError);
}
{
// load should throw if [validation_quorum] is
// missing from rippled cfg and validators file
boost::format cc ("[validators_file]\n%1%\n");
std::string error;
detail::ValidatorsTxtGuard const vtg (
*this, "test_cfg", "validators.cfg", boost::none);
BEAST_EXPECT(vtg.validatorsFileExists ());
auto const expectedError =
"The file specified in [validators_file] does not contain a "
"[validation_quorum] section: " + vtg.validatorsFile ();
try {
Config c;
c.loadFromString (boost::str (cc % vtg.validatorsFile ()));