Files
rippled/src/test/consensus/LedgerTrie_test.cpp
Bart 1eb0fdac65 refactor: Rename ripple namespace to xrpl (#5982)
This change renames all occurrences of `namespace ripple` and `ripple::` to `namespace xrpl` and `xrpl::`, respectively, as well as the names of test suites. It also provides a script to allow developers to replicate the changes in their local branch or fork to avoid conflicts.
2025-12-11 16:51:49 +00:00

665 lines
23 KiB
C++

#include <test/csf/ledgers.h>
#include <xrpld/consensus/LedgerTrie.h>
#include <xrpl/beast/unit_test.h>
#include <random>
namespace xrpl {
namespace test {
class LedgerTrie_test : public beast::unit_test::suite
{
void
testInsert()
{
using namespace csf;
// Single entry by itself
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
t.insert(h["abc"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
}
// Suffix of existing (extending tree)
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
BEAST_EXPECT(t.checkInvariants());
// extend with no siblings
t.insert(h["abcd"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
// extend with existing sibling
t.insert(h["abce"]);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 3);
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.tipSupport(h["abce"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abce"]) == 1);
}
// uncommitted of existing node
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abcd"]);
BEAST_EXPECT(t.checkInvariants());
// uncommitted with no siblings
t.insert(h["abcdf"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 2);
BEAST_EXPECT(t.tipSupport(h["abcdf"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcdf"]) == 1);
// uncommitted with existing child
t.insert(h["abc"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 3);
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 2);
BEAST_EXPECT(t.tipSupport(h["abcdf"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcdf"]) == 1);
}
// Suffix + uncommitted of existing node
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abcd"]);
BEAST_EXPECT(t.checkInvariants());
t.insert(h["abce"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.tipSupport(h["abce"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abce"]) == 1);
}
// Suffix + uncommitted with existing child
{
// abcd : abcde, abcf
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abcd"]);
BEAST_EXPECT(t.checkInvariants());
t.insert(h["abcde"]);
BEAST_EXPECT(t.checkInvariants());
t.insert(h["abcf"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 3);
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 2);
BEAST_EXPECT(t.tipSupport(h["abcf"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcf"]) == 1);
BEAST_EXPECT(t.tipSupport(h["abcde"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcde"]) == 1);
}
// Multiple counts
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["ab"], 4);
BEAST_EXPECT(t.tipSupport(h["ab"]) == 4);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 4);
BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
BEAST_EXPECT(t.branchSupport(h["a"]) == 4);
t.insert(h["abc"], 2);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
BEAST_EXPECT(t.tipSupport(h["ab"]) == 4);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 6);
BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
BEAST_EXPECT(t.branchSupport(h["a"]) == 6);
}
}
void
testRemove()
{
using namespace csf;
// Not in trie
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
BEAST_EXPECT(!t.remove(h["ab"]));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(!t.remove(h["a"]));
BEAST_EXPECT(t.checkInvariants());
}
// In trie but with 0 tip support
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abcd"]);
t.insert(h["abce"]);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
BEAST_EXPECT(!t.remove(h["abc"]));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
}
// In trie with > 1 tip support
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"], 2);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
BEAST_EXPECT(t.remove(h["abc"]));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
t.insert(h["abc"], 1);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
BEAST_EXPECT(t.remove(h["abc"], 2));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
t.insert(h["abc"], 3);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 3);
BEAST_EXPECT(t.remove(h["abc"], 300));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
}
// In trie with = 1 tip support, no children
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["ab"]);
t.insert(h["abc"]);
BEAST_EXPECT(t.tipSupport(h["ab"]) == 1);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 2);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
BEAST_EXPECT(t.remove(h["abc"]));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["ab"]) == 1);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 0);
}
// In trie with = 1 tip support, 1 child
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["ab"]);
t.insert(h["abc"]);
t.insert(h["abcd"]);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.remove(h["abc"]));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
}
// In trie with = 1 tip support, > 1 children
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["ab"]);
t.insert(h["abc"]);
t.insert(h["abcd"]);
t.insert(h["abce"]);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 3);
BEAST_EXPECT(t.remove(h["abc"]));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
}
// In trie with = 1 tip support, parent compaction
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["ab"]);
t.insert(h["abc"]);
t.insert(h["abd"]);
BEAST_EXPECT(t.checkInvariants());
t.remove(h["ab"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.tipSupport(h["abd"]) == 1);
BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 2);
t.remove(h["abd"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
}
}
void
testEmpty()
{
using namespace csf;
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
BEAST_EXPECT(t.empty());
Ledger genesis = h[""];
t.insert(genesis);
BEAST_EXPECT(!t.empty());
t.remove(genesis);
BEAST_EXPECT(t.empty());
t.insert(h["abc"]);
BEAST_EXPECT(!t.empty());
t.remove(h["abc"]);
BEAST_EXPECT(t.empty());
}
void
testSupport()
{
using namespace csf;
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
BEAST_EXPECT(t.tipSupport(h["axy"]) == 0);
BEAST_EXPECT(t.branchSupport(h["a"]) == 0);
BEAST_EXPECT(t.branchSupport(h["axy"]) == 0);
t.insert(h["abc"]);
BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.tipSupport(h["abcd"]) == 0);
BEAST_EXPECT(t.branchSupport(h["a"]) == 1);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abcd"]) == 0);
t.insert(h["abe"]);
BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
BEAST_EXPECT(t.tipSupport(h["abe"]) == 1);
BEAST_EXPECT(t.branchSupport(h["a"]) == 2);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 2);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abe"]) == 1);
t.remove(h["abc"]);
BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
BEAST_EXPECT(t.tipSupport(h["abe"]) == 1);
BEAST_EXPECT(t.branchSupport(h["a"]) == 1);
BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
BEAST_EXPECT(t.branchSupport(h["abc"]) == 0);
BEAST_EXPECT(t.branchSupport(h["abe"]) == 1);
}
void
testGetPreferred()
{
using namespace csf;
using Seq = Ledger::Seq;
// Empty
{
LedgerTrie<Ledger> t;
BEAST_EXPECT(t.getPreferred(Seq{0}) == std::nullopt);
BEAST_EXPECT(t.getPreferred(Seq{2}) == std::nullopt);
}
// Genesis support is NOT empty
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
Ledger genesis = h[""];
t.insert(genesis);
BEAST_EXPECT(t.getPreferred(Seq{0})->id == genesis.id());
BEAST_EXPECT(t.remove(genesis));
BEAST_EXPECT(t.getPreferred(Seq{0}) == std::nullopt);
BEAST_EXPECT(!t.remove(genesis));
}
// Single node no children
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
}
// Single node smaller child support
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
t.insert(h["abcd"]);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
}
// Single node larger child
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
t.insert(h["abcd"], 2);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcd"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
}
// Single node smaller children support
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
t.insert(h["abcd"]);
t.insert(h["abce"]);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
t.insert(h["abc"]);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
}
// Single node larger children
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
t.insert(h["abcd"], 2);
t.insert(h["abce"]);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
t.insert(h["abcd"]);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcd"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
}
// Tie-breaker by id
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abcd"], 2);
t.insert(h["abce"], 2);
BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abce"].id());
t.insert(h["abcd"]);
BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
}
// Tie-breaker not needed
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
t.insert(h["abcd"]);
t.insert(h["abce"], 2);
// abce only has a margin of 1, but it owns the tie-breaker
BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abce"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abce"].id());
// Switch support from abce to abcd, tie-breaker now needed
t.remove(h["abce"]);
t.insert(h["abcd"]);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
}
// Single node larger grand child
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
t.insert(h["abcd"], 2);
t.insert(h["abcde"], 4);
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcde"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcde"].id());
BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abcde"].id());
}
// Too much uncommitted support from competing branches
{
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["abc"]);
t.insert(h["abcde"], 2);
t.insert(h["abcfg"], 2);
// 'de' and 'fg' are tied without 'abc' vote
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abc"].id());
t.remove(h["abc"]);
t.insert(h["abcd"]);
// 'de' branch has 3 votes to 2, so earlier sequences see it as
// preferred
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcde"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcde"].id());
// However, if you validated a ledger with Seq 5, potentially on
// a different branch, you do not yet know if they chose abcd
// or abcf because of you, so abc remains preferred
BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abc"].id());
}
// Changing largestSeq perspective changes preferred branch
{
/** Build the tree below with initial tip support annotated
A
/ \
B(1) C(1)
/ | |
H D F(1)
|
E(2)
|
G
*/
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
t.insert(h["ab"]);
t.insert(h["ac"]);
t.insert(h["acf"]);
t.insert(h["abde"], 2);
// B has more branch support
BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
// But if you last validated D,F or E, you do not yet know
// if someone used that validation to commit to B or C
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["a"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
/** One of E advancing to G doesn't change anything
A
/ \
B(1) C(1)
/ | |
H D F(1)
|
E(1)
|
G(1)
*/
t.remove(h["abde"]);
t.insert(h["abdeg"]);
BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["a"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["a"].id());
/** C advancing to H does advance the seq 3 preferred ledger
A
/ \
B(1) C
/ | |
H(1)D F(1)
|
E(1)
|
G(1)
*/
t.remove(h["ac"]);
t.insert(h["abh"]);
BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["ab"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["a"].id());
/** F advancing to E also moves the preferred ledger forward
A
/ \
B(1) C
/ | |
H(1)D F
|
E(2)
|
G(1)
*/
t.remove(h["acf"]);
t.insert(h["abde"]);
BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["abde"].id());
BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["abde"].id());
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abde"].id());
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["ab"].id());
BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["ab"].id());
}
}
void
testRootRelated()
{
using namespace csf;
// Since the root is a special node that breaks the no-single child
// invariant, do some tests that exercise it.
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
BEAST_EXPECT(!t.remove(h[""]));
BEAST_EXPECT(t.branchSupport(h[""]) == 0);
BEAST_EXPECT(t.tipSupport(h[""]) == 0);
t.insert(h["a"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.branchSupport(h[""]) == 1);
BEAST_EXPECT(t.tipSupport(h[""]) == 0);
t.insert(h["e"]);
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.branchSupport(h[""]) == 2);
BEAST_EXPECT(t.tipSupport(h[""]) == 0);
BEAST_EXPECT(t.remove(h["e"]));
BEAST_EXPECT(t.checkInvariants());
BEAST_EXPECT(t.branchSupport(h[""]) == 1);
BEAST_EXPECT(t.tipSupport(h[""]) == 0);
}
void
testStress()
{
using namespace csf;
LedgerTrie<Ledger> t;
LedgerHistoryHelper h;
// Test quasi-randomly add/remove supporting for different ledgers
// from a branching history.
// Ledgers have sequence 1,2,3,4
std::uint32_t const depthConst = 4;
// Each ledger has 4 possible children
std::uint32_t const width = 4;
std::uint32_t const iterations = 10000;
// Use explicit seed to have same results for CI
std::mt19937 gen{42};
std::uniform_int_distribution<> depthDist(0, depthConst - 1);
std::uniform_int_distribution<> widthDist(0, width - 1);
std::uniform_int_distribution<> flip(0, 1);
for (std::uint32_t i = 0; i < iterations; ++i)
{
// pick a random ledger history
std::string curr = "";
char depth = depthDist(gen);
char offset = 0;
for (char d = 0; d < depth; ++d)
{
char a = offset + widthDist(gen);
curr += a;
offset = (a + 1) * width;
}
// 50-50 to add remove
if (flip(gen) == 0)
t.insert(h[curr]);
else
t.remove(h[curr]);
if (!BEAST_EXPECT(t.checkInvariants()))
return;
}
}
void
run() override
{
testInsert();
testRemove();
testEmpty();
testSupport();
testGetPreferred();
testRootRelated();
testStress();
}
};
BEAST_DEFINE_TESTSUITE(LedgerTrie, consensus, xrpl);
} // namespace test
} // namespace xrpl