1#include <test/jtx/Env.h> 
    2#include <test/unit_test/SuiteJournal.h> 
    4#include <xrpld/app/misc/AmendmentTable.h> 
    5#include <xrpld/core/ConfigSections.h> 
    7#include <xrpl/basics/BasicConfig.h> 
    8#include <xrpl/basics/Log.h> 
    9#include <xrpl/basics/chrono.h> 
   10#include <xrpl/beast/unit_test.h> 
   11#include <xrpl/protocol/Feature.h> 
   12#include <xrpl/protocol/PublicKey.h> 
   13#include <xrpl/protocol/STValidation.h> 
   14#include <xrpl/protocol/SecretKey.h> 
   15#include <xrpl/protocol/TxFlags.h> 
   16#include <xrpl/protocol/digest.h> 
   17#include <xrpl/protocol/jss.h> 
   42        for (
auto const& a : amendments)
 
 
   65        cfg->section(SECTION_AMENDMENTS) =
 
   67        cfg->section(SECTION_VETO_AMENDMENTS) =
 
 
   78        result.
reserve(amendments.size());
 
   79        for (
auto const& a : amendments)
 
 
  112    template <
class Arg, 
class... Args>
 
  116        if constexpr (
sizeof...(args) > 0)
 
 
  121    template <
class Arg, 
class... Args>
 
  130        if constexpr (
sizeof...(args) > 0)
 
 
  134    template <
class Arg, 
class... Args>
 
  143        left.reserve(
totalsize(left, right, args...));
 
 
  155        yes_{
"g", 
"i", 
"k", 
"m", 
"o", 
"q", 
"r", 
"s", 
"t", 
"u"};
 
  184            app, majorityTime, supported, enabled, vetoed, 
journal_);
 
 
  195        return makeTable(env.
app(), majorityTime, supported, enabled, vetoed);
 
 
  229        for (
auto const& a : 
yes_)
 
 
  256        for (
auto const& a : 
yes_)
 
  265            BEAST_EXPECT(!table->find(a));
 
  267            BEAST_EXPECT(!table->find(a));
 
  274                table->getJson(unsupportedID, 
true)[
to_string(unsupportedID)];
 
  275            BEAST_EXPECT(unsupp.
size() == 0);
 
  279        table->veto(unsupportedID);
 
  282                table->getJson(unsupportedID, 
true)[
to_string(unsupportedID)];
 
  283            BEAST_EXPECT(unsupp[jss::vetoed].asBool());
 
 
  304                    fail(
"Accepted only amendment ID");
 
  309                    e.
what() == 
"Invalid entry '" + 
id + 
"' in [Test]");
 
  315            test.
append(
id + 
" Test Name");
 
  321                    fail(
"Accepted extra arguments");
 
  327                    "Invalid entry '" + 
id + 
" Test Name' in [Test]");
 
  333            sid.resize(sid.length() - 1);
 
  336            test.
append(sid + 
" Name");
 
  342                    fail(
"Accepted short amendment ID");
 
  347                    e.
what() == 
"Invalid entry '" + sid + 
" Name' in [Test]");
 
  353            sid.resize(sid.length() + 1, 
'0');
 
  356            test.
append(sid + 
" Name");
 
  362                    fail(
"Accepted long amendment ID");
 
  367                    e.
what() == 
"Invalid entry '" + sid + 
" Name' in [Test]");
 
  373            sid.resize(sid.length() - 1);
 
  377            test.
append(sid + 
" Name");
 
  383                    fail(
"Accepted non-hex amendment ID");
 
  388                    e.
what() == 
"Invalid entry '" + sid + 
" Name' in [Test]");
 
 
  406        for (
uint256 const& a : allEnabled)
 
  407            BEAST_EXPECT(table->enable(a));
 
  410        BEAST_EXPECT(!table->hasUnsupportedEnabled());
 
  416            bool const enabled = table->isEnabled(supportedID);
 
  417            bool const found = allEnabled.
find(supportedID) != allEnabled.
end();
 
  420                a + (enabled ? 
" enabled " : 
" disabled ") +
 
  421                    (found ? 
" found" : 
" not found"));
 
  431            for (
uint256 const& a : desired)
 
  432                BEAST_EXPECT(vetoed.
count(a) == 0);
 
  438            BEAST_EXPECT(desired == table->getDesired());
 
  444            BEAST_EXPECT(table->unVeto(unvetoedID));
 
  457        BEAST_EXPECT(table->getDesired().empty());
 
  461            BEAST_EXPECT(!table->hasUnsupportedEnabled());
 
  463            BEAST_EXPECT(table->hasUnsupportedEnabled());
 
 
  475        trustedValidators.
reserve(num);
 
  476        for (
int i = 0; i < num; ++i)
 
  480            trustedValidators.
insert(back.first);
 
  482        table->trustChanged(trustedValidators);
 
 
  515        auto const roundTime = 
hourTime(hour);
 
  519        validations.
reserve(validators.size());
 
  522        for (
auto const& [pub, sec] : validators)
 
  527            for (
auto const& [hash, nVotes] : votes)
 
  532                    field.push_back(hash);
 
  545                    v.setFieldU32(sfLedgerSequence, 6180339);
 
  554            table.
doVoting(rules, roundTime, enabled, majority, validations);
 
  555        for (
auto const& [hash, action] : actions)
 
  563                    if (enabled.
find(hash) != enabled.
end())
 
  564                        Throw<std::runtime_error>(
"enabling already enabled");
 
  565                    if (majority.
find(hash) == majority.
end())
 
  566                        Throw<std::runtime_error>(
"enabling without majority");
 
  568                    majority.
erase(hash);
 
  572                    if (majority.
find(hash) != majority.
end())
 
  573                        Throw<std::runtime_error>(
 
  574                            "got majority while having majority");
 
  575                    majority[hash] = roundTime;
 
  579                    if (majority.
find(hash) == majority.
end())
 
  580                        Throw<std::runtime_error>(
 
  581                            "lost majority without majority");
 
  582                    majority.
erase(hash);
 
  586                    Throw<std::runtime_error>(
"unknown action");
 
 
  597        auto const testAmendment = 
amendmentId(
"TestAmendment");
 
  611            env.current()->rules(),
 
  619        BEAST_EXPECT(ourVotes.
empty());
 
  620        BEAST_EXPECT(enabled.
empty());
 
  621        BEAST_EXPECT(majority.
empty());
 
  626                table->getJson(unsupportedID, 
false)[
to_string(unsupportedID)];
 
  627            BEAST_EXPECT(unsupp.
size() == 0);
 
  630        table->veto(unsupportedID);
 
  633                table->getJson(unsupportedID, 
false)[
to_string(unsupportedID)];
 
  634            BEAST_EXPECT(!unsupp[jss::vetoed].asBool());
 
  642            env.current()->rules(),
 
  650        BEAST_EXPECT(ourVotes.
empty());
 
  651        BEAST_EXPECT(enabled.
empty());
 
  658            env.current()->rules(),
 
  666        BEAST_EXPECT(ourVotes.
empty());
 
  667        BEAST_EXPECT(enabled.
empty());
 
 
  676        auto const testAmendment = 
amendmentId(
"vetoedAmendment");
 
  694            env.current()->rules(),
 
  702        BEAST_EXPECT(ourVotes.
empty());
 
  703        BEAST_EXPECT(enabled.
empty());
 
  704        BEAST_EXPECT(majority.
empty());
 
  709            env.current()->rules(),
 
  717        BEAST_EXPECT(ourVotes.
empty());
 
  718        BEAST_EXPECT(enabled.
empty());
 
  723            env.current()->rules(),
 
  731        BEAST_EXPECT(ourVotes.
empty());
 
  732        BEAST_EXPECT(enabled.
empty());
 
 
  754            env.current()->rules(),
 
  763        BEAST_EXPECT(enabled.
empty());
 
  764        for (
auto const& i : 
yes_)
 
  768        for (
auto const& i : 
yes_)
 
  773            env.current()->rules(),
 
  782        BEAST_EXPECT(enabled.
empty());
 
  784        for (
auto const& i : 
yes_)
 
  789            env.current()->rules(),
 
  801            env.current()->rules(),
 
  810        BEAST_EXPECT(ourVotes.
empty());
 
  811        for (
auto const& i : 
yes_)
 
 
  821        auto const testAmendment = 
amendmentId(
"detectMajority");
 
  835        for (
int i = 0; i <= 17; ++i)
 
  840            if ((i > 0) && (i < 17))
 
  844                env.current()->rules(),
 
  856                BEAST_EXPECT(!ourVotes.
empty());
 
  857                BEAST_EXPECT(enabled.
empty());
 
  858                BEAST_EXPECT(majority.
empty());
 
  863                BEAST_EXPECT(!ourVotes.
empty());
 
  864                BEAST_EXPECT(!majority.
empty());
 
  865                BEAST_EXPECT(enabled.
empty());
 
  870                BEAST_EXPECT(!ourVotes.
empty());
 
  871                BEAST_EXPECT(majority.
empty());
 
  872                BEAST_EXPECT(!enabled.
empty());
 
  877                BEAST_EXPECT(ourVotes.
empty());
 
  878                BEAST_EXPECT(majority.
empty());
 
  879                BEAST_EXPECT(!enabled.
empty());
 
 
  890        auto const testAmendment = 
amendmentId(
"lostMajority");
 
  913                env.current()->rules(),
 
  922            BEAST_EXPECT(enabled.
empty());
 
  923            BEAST_EXPECT(!majority.
empty());
 
  926        for (
int i = 1; i < 8; ++i)
 
  932            votes.
emplace_back(testAmendment, validators.size() - i);
 
  935                env.current()->rules(),
 
  947                BEAST_EXPECT(!ourVotes.
empty());
 
  948                BEAST_EXPECT(enabled.
empty());
 
  949                BEAST_EXPECT(!majority.
empty());
 
  954                BEAST_EXPECT(!ourVotes.
empty());
 
  955                BEAST_EXPECT(majority.
empty());
 
  956                BEAST_EXPECT(enabled.
empty());
 
 
  967        auto const testAmendment = 
amendmentId(
"changedUNL");
 
  990                env.current()->rules(),
 
  999            BEAST_EXPECT(enabled.
empty());
 
 1000            BEAST_EXPECT(majority.
empty());
 
 1008        auto callTrustChanged =
 
 1017                    [&trustedValidators](
auto const& val) {
 
 1018                        trustedValidators.insert(val.first);
 
 1022                table->trustChanged(trustedValidators);
 
 1026        callTrustChanged(validators, table);
 
 1036                env.current()->rules(),
 
 1045            BEAST_EXPECT(enabled.
empty());
 
 1046            BEAST_EXPECT(!majority.
empty());
 
 1061                env.current()->rules(),
 
 1070            BEAST_EXPECT(enabled.
empty());
 
 1071            BEAST_EXPECT(majority.
empty());
 
 1075            validators.
insert(validators.
begin(), savedValidator);
 
 1077            votes.
front().second = validators.
size() - 2;
 
 1080                env.current()->rules(),
 
 1089            BEAST_EXPECT(enabled.
empty());
 
 1090            BEAST_EXPECT(!majority.
empty());
 
 1097            callTrustChanged(validators, table);
 
 1099            votes.
front().second = validators.
size() - 2;
 
 1102                env.current()->rules(),
 
 1111            BEAST_EXPECT(enabled.
empty());
 
 1112            BEAST_EXPECT(majority.
empty());
 
 
 1130        for (
int flapRateHours : {23, 25})
 
 1133            auto const testAmendment = 
amendmentId(
"validatorFlapping");
 
 1144            decltype(allValidators) 
const mostValidators(
 
 1145                allValidators.begin() + 1, allValidators.end());
 
 1146            BEAST_EXPECT(allValidators.size() == mostValidators.size() + 1);
 
 1154            votes.
emplace_back(testAmendment, allValidators.size() - 2);
 
 1156            int delay = flapRateHours;
 
 1158            for (
int hour = 1; hour < (24 * 8); ++hour)
 
 1160                decltype(allValidators) 
const& thisHoursValidators =
 
 1161                    (delay < flapRateHours) ? mostValidators : allValidators;
 
 1162                delay = delay == flapRateHours ? 0 : delay + 1;
 
 1164                votes.
front().second = thisHoursValidators.size() - 2;
 
 1168                    env.current()->rules(),
 
 1171                    thisHoursValidators,
 
 1177                if (hour <= (24 * 7) || flapRateHours > 24)
 
 1181                    BEAST_EXPECT(enabled.
empty());
 
 1187                    bool const expectMajority = (delay <= 24)
 
 1189                        : &thisHoursValidators == &allValidators;
 
 1190                    BEAST_EXPECT(majority.
empty() != expectMajority);
 
 1198                    BEAST_EXPECT(!enabled.
empty());
 
 1199                    BEAST_EXPECT(majority.
empty());
 
 
 1210        using namespace std::chrono_literals;
 
 1211        weeks constexpr w(1);
 
 1214        BEAST_EXPECT(!table->hasUnsupportedEnabled());
 
 1215        BEAST_EXPECT(!table->firstUnsupportedExpected());
 
 1216        BEAST_EXPECT(table->needValidatedLedger(1));
 
 1222            [&enabled](
auto const& s) { enabled.insert(amendmentId(s)); });
 
 1225        table->doValidatedLedger(1, enabled, majority);
 
 1226        BEAST_EXPECT(table->hasUnsupportedEnabled());
 
 1227        BEAST_EXPECT(!table->firstUnsupportedExpected());
 
 1233            [&majority, &t](
auto const& s) {
 
 1234                majority[amendmentId(s)] = NetClock::time_point{--t};
 
 1237        table->doValidatedLedger(1, enabled, majority);
 
 1238        BEAST_EXPECT(table->hasUnsupportedEnabled());
 
 1240            table->firstUnsupportedExpected() &&
 
 1244        BEAST_EXPECT(!table->needValidatedLedger(256));
 
 1245        BEAST_EXPECT(table->needValidatedLedger(257));
 
 
 1251        testNoOnUnknown(feat);
 
 1252        testNoOnVetoed(feat);
 
 1253        testVoteEnable(feat);
 
 1254        testDetectMajority(feat);
 
 1255        testLostMajority(feat);
 
 1256        testChangedUNL(feat);
 
 1257        testValidatorFlapping(feat);
 
 
 1269        testHasUnsupported();
 
 
 
T back_inserter(T... args)
 
UInt size() const
Number of values in array or object.
 
testcase_t testcase
Memberspace for declaring test cases.
 
void fail(String const &reason, char const *file, int line)
Record a failure.
 
void testNoOnVetoed(FeatureBitset const &feat)
 
static std::vector< AmendmentTable::FeatureInfo > makeObsolete(std::vector< std::string > const &amendments)
 
static Section makeSection(std::vector< std::string > const &amendments)
 
static uint256 amendmentId(std::string in)
 
void testDetectMajority(FeatureBitset const &feat)
 
std::unique_ptr< AmendmentTable > makeTable(test::jtx::Env &env, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed)
 
static std::vector< AmendmentTable::FeatureInfo > makeDefaultYes(std::vector< std::string > const &amendments)
 
std::vector< std::string > const obsolete_
 
std::vector< std::string > const unsupportedMajority_
 
static void combine_arg(std::vector< Arg > &dest, std::vector< Arg > const &src, Args const &... args)
 
void testChangedUNL(FeatureBitset const &feat)
 
std::unique_ptr< AmendmentTable > makeTable(test::jtx::Env &env, std::chrono::seconds majorityTime)
 
std::vector< std::string > const enabled_
 
test::SuiteJournal journal_
 
void testValidatorFlapping(FeatureBitset const &feat)
 
std::unique_ptr< Config > makeConfig()
 
std::vector< std::string > const vetoed_
 
void testFeature(FeatureBitset const &feat)
 
std::vector< std::string > const unsupported_
 
std::unique_ptr< AmendmentTable > makeTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed)
 
static NetClock::time_point hourTime(std::chrono::hours h)
 
static Section makeSection(std::string const &name, std::vector< std::string > const &amendments)
 
static std::vector< Arg > combine(std::vector< Arg > left, std::vector< Arg > const &right, Args const &... args)
 
void testNoOnUnknown(FeatureBitset const &feat)
 
Section const emptySection_
 
void doRound(Rules const &rules, AmendmentTable &table, std::chrono::hours hour, std::vector< std::pair< PublicKey, SecretKey > > const &validators, std::vector< std::pair< uint256, int > > const &votes, std::vector< uint256 > &ourVotes, std::set< uint256 > &enabled, majorityAmendments_t &majority)
 
static size_t totalsize(std::vector< Arg > const &src, Args const &... args)
 
static std::vector< AmendmentTable::FeatureInfo > makeFeatureInfo(std::vector< std::string > const &amendments, VoteBehavior voteBehavior)
 
std::vector< std::string > const allSupported_
 
static std::vector< AmendmentTable::FeatureInfo > makeDefaultNo(std::vector< std::string > const &amendments)
 
static std::vector< AmendmentTable::FeatureInfo > makeDefaultYes(uint256 const amendment)
 
static Section makeSection(uint256 const &amendment)
 
std::vector< std::string > const yes_
 
void testLostMajority(FeatureBitset const &feat)
 
std::vector< std::pair< PublicKey, SecretKey > > makeValidators(int num, std::unique_ptr< AmendmentTable > const &table)
 
std::vector< AmendmentTable::FeatureInfo > const emptyYes_
 
void testHasUnsupported()
 
void run() override
Runs the suite.
 
void testVoteEnable(FeatureBitset const &feat)
 
The amendment table stores the list of enabled and potential amendments.
 
virtual std::vector< uint256 > doValidation(std::set< uint256 > const &enabled) const =0
 
virtual std::map< uint256, std::uint32_t > doVoting(Rules const &rules, NetClock::time_point closeTime, std::set< uint256 > const &enabledAmendments, majorityAmendments_t const &majorityAmendments, std::vector< std::shared_ptr< STValidation > > const &valSet)=0
 
Rules controlling protocol behavior.
 
Holds a collection of configuration values.
 
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
 
static constexpr std::size_t size()
 
A transaction testing environment.
 
T emplace_back(T... args)
 
std::enable_if_t< is_contiguously_hashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
 
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
 
FeatureBitset testable_amendments()
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
void hash_append(Hasher &h, Slice const &v)
 
constexpr std::uint32_t tfGotMajority
 
std::chrono::duration< int, std::ratio_multiply< days::period, std::ratio< 7 > > > weeks
 
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
 
std::string to_string(base_uint< Bits, Tag > const &a)
 
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
 
std::unique_ptr< AmendmentTable > make_AmendmentTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
 
constexpr std::uint32_t tfLostMajority