Refactor Feature name management and creation:

* Only require adding the new feature names in one place. (Also need to
  increment a counter, but a check on startup will catch that.)
* Allows rippled to have the code to support a given amendment, but
  not vote for it by default. This allows the amendment to be enabled in
  a future version without necessarily amendment blocking these older
  versions.
* The default vote is carried with the amendment name in the list of
  supported amendments.
* The amendment table is constructed with the amendment and default
  vote.
This commit is contained in:
Edward Hennis
2020-06-13 22:56:36 -04:00
committed by manojsdoshi
parent 1ca8898703
commit 4a9bd7ed6d
13 changed files with 837 additions and 490 deletions

View File

@@ -86,11 +86,31 @@ private:
return cfg;
}
static std::vector<AmendmentTable::FeatureInfo>
makeDefaultYes(std::vector<std::string> const& amendments)
{
std::vector<AmendmentTable::FeatureInfo> result;
result.reserve(amendments.size());
for (auto const& a : amendments)
{
result.emplace_back(a, amendmentId(a), DefaultVote::yes);
}
return result;
}
static std::vector<AmendmentTable::FeatureInfo>
makeDefaultYes(uint256 const amendment)
{
std::vector<AmendmentTable::FeatureInfo> result{
{to_string(amendment), amendment, DefaultVote::yes}};
return result;
}
// All useful amendments are supported amendments.
// Enabled amendments are typically a subset of supported amendments.
// Vetoed amendments should be supported but not enabled.
// Unsupported amendments may be added to the AmendmentTable.
std::vector<std::string> const supported_{
std::vector<std::string> const supportedYes_{
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
"l", "m", "n", "o", "p", "q", "r", "s", "t", "u"};
std::vector<std::string> const
@@ -100,6 +120,7 @@ private:
std::vector<std::string> const unsupportedMajority_{"y", "z"};
Section const emptySection;
std::vector<AmendmentTable::FeatureInfo> const emptyYes;
test::SuiteJournal journal;
@@ -112,7 +133,7 @@ public:
makeTable(
Application& app,
std::chrono::seconds majorityTime,
Section const& supported,
std::vector<AmendmentTable::FeatureInfo> const& supported,
Section const& enabled,
Section const& vetoed)
{
@@ -124,7 +145,7 @@ public:
makeTable(
test::jtx::Env& env,
std::chrono::seconds majorityTime,
Section const& supported,
std::vector<AmendmentTable::FeatureInfo> const& supported,
Section const& enabled,
Section const& vetoed)
{
@@ -137,7 +158,7 @@ public:
return makeTable(
env.app(),
majorityTime,
makeSection(supported_),
makeDefaultYes(supportedYes_),
makeSection(enabled_),
makeSection(vetoed_));
}
@@ -149,7 +170,7 @@ public:
test::jtx::Env env{*this, makeConfig()};
auto table = makeTable(env, weeks(1));
for (auto const& a : supported_)
for (auto const& a : supportedYes_)
{
BEAST_EXPECT(table->isSupported(amendmentId(a)));
}
@@ -174,7 +195,7 @@ public:
test::jtx::Env env{*this, makeConfig()};
auto table = makeTable(env, weeks(1));
for (auto const& a : supported_)
for (auto const& a : supportedYes_)
BEAST_EXPECT(table->find(a) == amendmentId(a));
for (auto const& a : enabled_)
BEAST_EXPECT(table->find(a) == amendmentId(a));
@@ -207,7 +228,8 @@ public:
void
testBadConfig()
{
auto const section = makeSection(supported_);
auto const yesVotes = makeDefaultYes(supportedYes_);
auto const section = makeSection(vetoed_);
auto const id = to_string(amendmentId(enabled_[0]));
testcase("Bad Config");
@@ -219,12 +241,13 @@ public:
try
{
test::jtx::Env env{*this, makeConfig()};
if (makeTable(env, weeks(2), test, emptySection, emptySection))
if (makeTable(env, weeks(2), yesVotes, test, emptySection))
fail("Accepted only amendment ID");
}
catch (...)
catch (std::exception const& e)
{
pass();
BEAST_EXPECT(
e.what() == "Invalid entry '" + id + "' in [Test]");
}
}
@@ -235,12 +258,14 @@ public:
try
{
test::jtx::Env env{*this, makeConfig()};
if (makeTable(env, weeks(2), test, emptySection, emptySection))
if (makeTable(env, weeks(2), yesVotes, test, emptySection))
fail("Accepted extra arguments");
}
catch (...)
catch (std::exception const& e)
{
pass();
BEAST_EXPECT(
e.what() ==
"Invalid entry '" + id + " Test Name' in [Test]");
}
}
@@ -254,12 +279,13 @@ public:
try
{
test::jtx::Env env{*this, makeConfig()};
if (makeTable(env, weeks(2), test, emptySection, emptySection))
if (makeTable(env, weeks(2), yesVotes, test, emptySection))
fail("Accepted short amendment ID");
}
catch (...)
catch (std::exception const& e)
{
pass();
BEAST_EXPECT(
e.what() == "Invalid entry '" + sid + " Name' in [Test]");
}
}
@@ -273,12 +299,13 @@ public:
try
{
test::jtx::Env env{*this, makeConfig()};
if (makeTable(env, weeks(2), test, emptySection, emptySection))
if (makeTable(env, weeks(2), yesVotes, test, emptySection))
fail("Accepted long amendment ID");
}
catch (...)
catch (std::exception const& e)
{
pass();
BEAST_EXPECT(
e.what() == "Invalid entry '" + sid + " Name' in [Test]");
}
}
@@ -293,12 +320,13 @@ public:
try
{
test::jtx::Env env{*this, makeConfig()};
if (makeTable(env, weeks(2), test, emptySection, emptySection))
if (makeTable(env, weeks(2), yesVotes, test, emptySection))
fail("Accepted non-hex amendment ID");
}
catch (...)
catch (std::exception const& e)
{
pass();
BEAST_EXPECT(
e.what() == "Invalid entry '" + sid + " Name' in [Test]");
}
}
}
@@ -311,27 +339,27 @@ public:
test::jtx::Env env{*this, makeConfig()};
std::unique_ptr<AmendmentTable> table = makeTable(env, weeks(2));
// Note which entries are enabled.
// Note which entries are enabled
std::set<uint256> allEnabled;
// Subset of amendments to enable
allEnabled.insert(amendmentId(supported_[0]));
allEnabled.insert(amendmentId(enabled_[0]));
allEnabled.insert(amendmentId(vetoed_[0]));
for (auto const& a : enabled_)
allEnabled.insert(amendmentId(a));
for (uint256 const& a : allEnabled)
table->enable(a);
BEAST_EXPECT(table->enable(a));
// So far all enabled amendments are supported.
BEAST_EXPECT(!table->hasUnsupportedEnabled());
// Verify all enables are enabled and nothing else.
for (std::string const& a : supported_)
for (std::string const& a : supportedYes_)
{
uint256 const supportedID = amendmentId(a);
BEAST_EXPECT(
table->isEnabled(supportedID) ==
(allEnabled.find(supportedID) != allEnabled.end()));
bool const enabled = table->isEnabled(supportedID);
bool const found = allEnabled.find(supportedID) != allEnabled.end();
BEAST_EXPECTS(
enabled == found,
a + (enabled ? " enabled " : " disabled ") +
(found ? " found" : " not found"));
}
// All supported and unVetoed amendments should be returned as desired.
@@ -347,14 +375,14 @@ public:
// Unveto an amendment that is already not vetoed. Shouldn't
// hurt anything, but the values returned by getDesired()
// shouldn't change.
table->unVeto(amendmentId(supported_[1]));
BEAST_EXPECT(!table->unVeto(amendmentId(supportedYes_[1])));
BEAST_EXPECT(desired == table->getDesired());
}
// UnVeto one of the vetoed amendments. It should now be desired.
{
uint256 const unvetoedID = amendmentId(vetoed_[0]);
table->unVeto(unvetoedID);
BEAST_EXPECT(table->unVeto(unvetoedID));
std::vector<uint256> const desired = table->getDesired();
BEAST_EXPECT(
@@ -363,7 +391,7 @@ public:
}
// Veto all supported amendments. Now desired should be empty.
for (std::string const& a : supported_)
for (std::string const& a : supportedYes_)
{
table->veto(amendmentId(a));
}
@@ -505,7 +533,7 @@ public:
test::jtx::Env env{*this};
auto table =
makeTable(env, weeks(2), emptySection, emptySection, emptySection);
makeTable(env, weeks(2), emptyYes, emptySection, emptySection);
std::vector<std::pair<uint256, int>> votes;
std::vector<uint256> ourVotes;
@@ -566,11 +594,7 @@ public:
test::jtx::Env env{*this};
auto table = makeTable(
env,
weeks(2),
emptySection,
emptySection,
makeSection(testAmendment));
env, weeks(2), emptyYes, emptySection, makeSection(testAmendment));
auto const validators = makeValidators(10);
@@ -629,7 +653,11 @@ public:
test::jtx::Env env{*this};
auto table = makeTable(
env, weeks(2), makeSection(supported_), emptySection, emptySection);
env,
weeks(2),
makeDefaultYes(supportedYes_),
emptySection,
emptySection);
auto const validators = makeValidators(10);
std::vector<std::pair<uint256, int>> votes;
@@ -647,13 +675,13 @@ public:
ourVotes,
enabled,
majority);
BEAST_EXPECT(ourVotes.size() == supported_.size());
BEAST_EXPECT(ourVotes.size() == supportedYes_.size());
BEAST_EXPECT(enabled.empty());
for (auto const& i : supported_)
for (auto const& i : supportedYes_)
BEAST_EXPECT(majority.find(amendmentId(i)) == majority.end());
// Now, everyone votes for this feature
for (auto const& i : supported_)
for (auto const& i : supportedYes_)
votes.emplace_back(amendmentId(i), validators.size());
// Week 2: We should recognize a majority
@@ -666,10 +694,10 @@ public:
ourVotes,
enabled,
majority);
BEAST_EXPECT(ourVotes.size() == supported_.size());
BEAST_EXPECT(ourVotes.size() == supportedYes_.size());
BEAST_EXPECT(enabled.empty());
for (auto const& i : supported_)
for (auto const& i : supportedYes_)
BEAST_EXPECT(majority[amendmentId(i)] == weekTime(weeks{2}));
// Week 5: We should enable the amendment
@@ -682,7 +710,7 @@ public:
ourVotes,
enabled,
majority);
BEAST_EXPECT(enabled.size() == supported_.size());
BEAST_EXPECT(enabled.size() == supportedYes_.size());
// Week 6: We should remove it from our votes and from having a majority
doRound(
@@ -694,9 +722,9 @@ public:
ourVotes,
enabled,
majority);
BEAST_EXPECT(enabled.size() == supported_.size());
BEAST_EXPECT(enabled.size() == supportedYes_.size());
BEAST_EXPECT(ourVotes.empty());
for (auto const& i : supported_)
for (auto const& i : supportedYes_)
BEAST_EXPECT(majority.find(amendmentId(i)) == majority.end());
}
@@ -711,7 +739,7 @@ public:
auto table = makeTable(
env,
weeks(2),
makeSection(testAmendment),
makeDefaultYes(testAmendment),
emptySection,
emptySection);
@@ -782,7 +810,7 @@ public:
auto table = makeTable(
env,
weeks(8),
makeSection(testAmendment),
makeDefaultYes(testAmendment),
emptySection,
emptySection);