Files
rippled/src/test/consensus/LedgerTrie_test.cpp
Bart 1d42c4f6de refactor: Remove unnecessary copyright notices already covered by LICENSE.md (#5929)
Per XLS-0095, we are taking steps to rename ripple(d) to xrpl(d).

This change specifically removes all copyright notices referencing Ripple, XRPLF, and certain affiliated contributors upon mutual agreement, so the notice in the LICENSE.md file applies throughout. Copyright notices referencing external contributions remain as-is. Duplicate verbiage is also removed.
2025-11-04 08:33:42 +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 ripple {
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, ripple);
} // namespace test
} // namespace ripple