mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Improve preferred ledger calculation:
This changeset ensures the preferred ledger calculation properly distinguishes the absence of trusted validations from a preferred ledger which is the genesis ledger.
This commit is contained in:
@@ -29,7 +29,7 @@
|
||||
namespace ripple {
|
||||
|
||||
/** The tip of a span of ledger ancestry
|
||||
*/
|
||||
*/
|
||||
template <class Ledger>
|
||||
class SpanTip
|
||||
{
|
||||
@@ -461,7 +461,7 @@ public:
|
||||
newNode->branchSupport = loc->branchSupport;
|
||||
newNode->children = std::move(loc->children);
|
||||
assert(loc->children.empty());
|
||||
for(std::unique_ptr<Node> & child : newNode->children)
|
||||
for (std::unique_ptr<Node>& child : newNode->children)
|
||||
child->parent = newNode.get();
|
||||
|
||||
// Loc truncates to prefix and newNode is its child
|
||||
@@ -512,8 +512,7 @@ public:
|
||||
Seq diffSeq;
|
||||
std::tie(loc, diffSeq) = find(ledger);
|
||||
|
||||
// Cannot erase root
|
||||
if (loc && loc != root.get())
|
||||
if (loc)
|
||||
{
|
||||
// Must be exact match with tip support
|
||||
if (diffSeq == loc->span.end() && diffSeq > ledger.seq() &&
|
||||
@@ -525,7 +524,7 @@ public:
|
||||
auto const it = seqSupport.find(ledger.seq());
|
||||
assert(it != seqSupport.end() && it->second >= count);
|
||||
it->second -= count;
|
||||
if(it->second == 0)
|
||||
if (it->second == 0)
|
||||
seqSupport.erase(it->first);
|
||||
|
||||
Node* decNode = loc;
|
||||
@@ -584,7 +583,8 @@ public:
|
||||
/** Return the count of branch support for the specific ledger
|
||||
|
||||
@param ledger The ledger to lookup
|
||||
@return The number of entries in the trie for this ledger or a descendant
|
||||
@return The number of entries in the trie for this ledger or a
|
||||
descendant
|
||||
*/
|
||||
std::uint32_t
|
||||
branchSupport(Ledger const& ledger) const
|
||||
@@ -595,8 +595,7 @@ public:
|
||||
|
||||
// Check that ledger is is an exact match or proper
|
||||
// prefix of loc
|
||||
if (loc && diffSeq > ledger.seq() &&
|
||||
ledger.seq() < loc->span.end())
|
||||
if (loc && diffSeq > ledger.seq() && ledger.seq() < loc->span.end())
|
||||
{
|
||||
return loc->branchSupport;
|
||||
}
|
||||
@@ -659,11 +658,15 @@ public:
|
||||
|
||||
@param largestIssued The sequence number of the largest validation
|
||||
issued by this node.
|
||||
@return Pair with the sequence number and ID of the preferred ledger
|
||||
@return Pair with the sequence number and ID of the preferred ledger or
|
||||
boost::none if no preferred ledger exists
|
||||
*/
|
||||
SpanTip<Ledger>
|
||||
boost::optional<SpanTip<Ledger>>
|
||||
getPreferred(Seq const largestIssued) const
|
||||
{
|
||||
if (empty())
|
||||
return boost::none;
|
||||
|
||||
Node* curr = root.get();
|
||||
|
||||
bool done = false;
|
||||
@@ -699,7 +702,7 @@ public:
|
||||
uncommitted += uncommittedIt->second;
|
||||
uncommittedIt++;
|
||||
}
|
||||
else // otherwise we jump to the end of the span
|
||||
else // otherwise we jump to the end of the span
|
||||
nextSeq = curr->span.end();
|
||||
}
|
||||
// We did not consume the entire span, so we have found the
|
||||
@@ -727,8 +730,10 @@ public:
|
||||
curr->children.end(),
|
||||
[](std::unique_ptr<Node> const& a,
|
||||
std::unique_ptr<Node> const& b) {
|
||||
return std::make_tuple(a->branchSupport, a->span.startID()) >
|
||||
std::make_tuple(b->branchSupport, b->span.startID());
|
||||
return std::make_tuple(
|
||||
a->branchSupport, a->span.startID()) >
|
||||
std::make_tuple(
|
||||
b->branchSupport, b->span.startID());
|
||||
});
|
||||
|
||||
best = curr->children[0].get();
|
||||
@@ -752,6 +757,14 @@ public:
|
||||
return curr->span.tip();
|
||||
}
|
||||
|
||||
/** Return whether the trie is tracking any ledgers
|
||||
*/
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return !root || root->branchSupport == 0;
|
||||
}
|
||||
|
||||
/** Dump an ascii representation of the trie to the stream
|
||||
*/
|
||||
void
|
||||
@@ -761,7 +774,7 @@ public:
|
||||
}
|
||||
|
||||
/** Dump JSON representation of trie state
|
||||
*/
|
||||
*/
|
||||
Json::Value
|
||||
getJson() const
|
||||
{
|
||||
@@ -798,7 +811,7 @@ public:
|
||||
|
||||
for (auto const& child : curr->children)
|
||||
{
|
||||
if(child->parent != curr)
|
||||
if (child->parent != curr)
|
||||
return false;
|
||||
|
||||
support += child->branchSupport;
|
||||
|
||||
@@ -87,6 +87,7 @@ class SeqEnforcer
|
||||
using time_point = std::chrono::steady_clock::time_point;
|
||||
Seq seq_{0};
|
||||
time_point when_;
|
||||
|
||||
public:
|
||||
/** Try advancing the largest observed validation ledger sequence
|
||||
|
||||
@@ -101,11 +102,11 @@ public:
|
||||
@return Whether the validation satisfies the invariant
|
||||
*/
|
||||
bool
|
||||
operator()(time_point now, Seq s, ValidationParms const & p)
|
||||
operator()(time_point now, Seq s, ValidationParms const& p)
|
||||
{
|
||||
if(now > (when_ + p.validationSET_EXPIRES))
|
||||
if (now > (when_ + p.validationSET_EXPIRES))
|
||||
seq_ = Seq{0};
|
||||
if(s <= seq_)
|
||||
if (s <= seq_)
|
||||
return false;
|
||||
seq_ = s;
|
||||
when_ = now;
|
||||
@@ -147,7 +148,6 @@ isCurrent(
|
||||
(seenTime < (now + p.validationCURRENT_LOCAL)));
|
||||
}
|
||||
|
||||
|
||||
/** Status of newly received validation
|
||||
*/
|
||||
enum class ValStatus {
|
||||
@@ -233,8 +233,8 @@ to_string(ValStatus m)
|
||||
// Whether this is a full or partial validation
|
||||
bool full() const;
|
||||
|
||||
// Identifier for this node that remains fixed even when rotating signing
|
||||
// keys
|
||||
// Identifier for this node that remains fixed even when rotating
|
||||
// signing keys
|
||||
NodeID nodeID() const;
|
||||
|
||||
implementation_specific_t
|
||||
@@ -312,7 +312,7 @@ class Validations
|
||||
hash_map<NodeID, Ledger> lastLedger_;
|
||||
|
||||
// Set of ledgers being acquired from the network
|
||||
hash_map<std::pair<Seq,ID>, hash_set<NodeID>> acquiring_;
|
||||
hash_map<std::pair<Seq, ID>, hash_set<NodeID>> acquiring_;
|
||||
|
||||
// Parameters to determine validation staleness
|
||||
ValidationParms const parms_;
|
||||
@@ -327,7 +327,8 @@ private:
|
||||
removeTrie(ScopedLock const&, NodeID const& nodeID, Validation const& val)
|
||||
{
|
||||
{
|
||||
auto it = acquiring_.find(std::make_pair(val.seq(), val.ledgerID()));
|
||||
auto it =
|
||||
acquiring_.find(std::make_pair(val.seq(), val.ledgerID()));
|
||||
if (it != acquiring_.end())
|
||||
{
|
||||
it->second.erase(nodeID);
|
||||
@@ -387,7 +388,8 @@ private:
|
||||
@param lock Existing lock of mutex_
|
||||
@param nodeID The node identifier of the validating node
|
||||
@param val The trusted validation issued by the node
|
||||
@param prior If not none, the last current validated ledger Seq,ID of key
|
||||
@param prior If not none, the last current validated ledger Seq,ID of
|
||||
key
|
||||
*/
|
||||
void
|
||||
updateTrie(
|
||||
@@ -445,7 +447,7 @@ private:
|
||||
withTrie(ScopedLock const& lock, F&& f)
|
||||
{
|
||||
// Call current to flush any stale validations
|
||||
current(lock, [](auto){}, [](auto, auto){});
|
||||
current(lock, [](auto) {}, [](auto, auto) {});
|
||||
checkAcquired(lock);
|
||||
return f(trie_);
|
||||
}
|
||||
@@ -537,8 +539,8 @@ public:
|
||||
}
|
||||
|
||||
/** Return the adaptor instance
|
||||
*/
|
||||
Adaptor const &
|
||||
*/
|
||||
Adaptor const&
|
||||
adaptor() const
|
||||
{
|
||||
return adaptor_;
|
||||
@@ -552,8 +554,8 @@ public:
|
||||
return parms_;
|
||||
}
|
||||
|
||||
/** Return whether the local node can issue a validation for the given sequence
|
||||
number
|
||||
/** Return whether the local node can issue a validation for the given
|
||||
sequence number
|
||||
|
||||
@param s The sequence number of the ledger the node wants to validate
|
||||
@return Whether the validation satisfies the invariant, updating the
|
||||
@@ -602,7 +604,7 @@ public:
|
||||
Validation& oldVal = ins.first->second;
|
||||
if (val.signTime() > oldVal.signTime())
|
||||
{
|
||||
std::pair<Seq,ID> old(oldVal.seq(),oldVal.ledgerID());
|
||||
std::pair<Seq, ID> old(oldVal.seq(), oldVal.ledgerID());
|
||||
adaptor_.onStale(std::move(oldVal));
|
||||
ins.first->second = val;
|
||||
if (val.trusted())
|
||||
@@ -691,20 +693,19 @@ public:
|
||||
@param curr The local node's current working ledger
|
||||
|
||||
@return The sequence and id of the preferred working ledger,
|
||||
or Seq{0},ID{0} if no trusted validations are available to
|
||||
or boost::none if no trusted validations are available to
|
||||
determine the preferred ledger.
|
||||
*/
|
||||
std::pair<Seq, ID>
|
||||
boost::optional<std::pair<Seq, ID>>
|
||||
getPreferred(Ledger const& curr)
|
||||
{
|
||||
ScopedLock lock{mutex_};
|
||||
SpanTip<Ledger> preferred =
|
||||
boost::optional<SpanTip<Ledger>> preferred =
|
||||
withTrie(lock, [this](LedgerTrie<Ledger>& trie) {
|
||||
return trie.getPreferred(localSeqEnforcer_.largest());
|
||||
});
|
||||
|
||||
// No trusted validations to determine branch
|
||||
if (preferred.seq == Seq{0})
|
||||
if (!preferred)
|
||||
{
|
||||
// fall back to majority over acquiring ledgers
|
||||
auto it = std::max_element(
|
||||
@@ -722,26 +723,26 @@ public:
|
||||
return std::tie(aSize, aKey.second) <
|
||||
std::tie(bSize, bKey.second);
|
||||
});
|
||||
if(it != acquiring_.end())
|
||||
if (it != acquiring_.end())
|
||||
return it->first;
|
||||
return std::make_pair(preferred.seq, preferred.id);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
// If we are the parent of the preferred ledger, stick with our
|
||||
// current ledger since we might be about to generate it
|
||||
if (preferred.seq == curr.seq() + Seq{1} &&
|
||||
preferred.ancestor(curr.seq()) == curr.id())
|
||||
if (preferred->seq == curr.seq() + Seq{1} &&
|
||||
preferred->ancestor(curr.seq()) == curr.id())
|
||||
return std::make_pair(curr.seq(), curr.id());
|
||||
|
||||
// A ledger ahead of us is preferred regardless of whether it is
|
||||
// a descendant of our working ledger or it is on a different chain
|
||||
if (preferred.seq > curr.seq())
|
||||
return std::make_pair(preferred.seq, preferred.id);
|
||||
if (preferred->seq > curr.seq())
|
||||
return std::make_pair(preferred->seq, preferred->id);
|
||||
|
||||
// Only switch to earlier or same sequence number
|
||||
// if it is a different chain.
|
||||
if (curr[preferred.seq] != preferred.id)
|
||||
return std::make_pair(preferred.seq, preferred.id);
|
||||
if (curr[preferred->seq] != preferred->id)
|
||||
return std::make_pair(preferred->seq, preferred->id);
|
||||
|
||||
// Stick with current ledger
|
||||
return std::make_pair(curr.seq(), curr.id());
|
||||
@@ -759,22 +760,21 @@ public:
|
||||
ID
|
||||
getPreferred(Ledger const& curr, Seq minValidSeq)
|
||||
{
|
||||
std::pair<Seq, ID> preferred = getPreferred(curr);
|
||||
if(preferred.first >= minValidSeq && preferred.second != ID{0})
|
||||
return preferred.second;
|
||||
boost::optional<std::pair<Seq, ID>> preferred = getPreferred(curr);
|
||||
if (preferred && preferred->first >= minValidSeq)
|
||||
return preferred->second;
|
||||
return curr.id();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Determine the preferred last closed ledger for the next consensus round.
|
||||
|
||||
Called before starting the next round of ledger consensus to determine the
|
||||
preferred working ledger. Uses the dominant peerCount ledger if no
|
||||
Called before starting the next round of ledger consensus to determine
|
||||
the preferred working ledger. Uses the dominant peerCount ledger if no
|
||||
trusted validations are available.
|
||||
|
||||
@param lcl Last closed ledger by this node
|
||||
@param minSeq Minimum allowed sequence number of the trusted preferred ledger
|
||||
@param minSeq Minimum allowed sequence number of the trusted preferred
|
||||
ledger
|
||||
@param peerCounts Map from ledger ids to count of peers with that as the
|
||||
last closed ledger
|
||||
@return The preferred last closed ledger ID
|
||||
@@ -784,15 +784,16 @@ public:
|
||||
*/
|
||||
ID
|
||||
getPreferredLCL(
|
||||
Ledger const & lcl,
|
||||
Ledger const& lcl,
|
||||
Seq minSeq,
|
||||
hash_map<ID, std::uint32_t> const& peerCounts)
|
||||
{
|
||||
std::pair<Seq, ID> preferred = getPreferred(lcl);
|
||||
boost::optional<std::pair<Seq, ID>> preferred = getPreferred(lcl);
|
||||
|
||||
// Trusted validations exist
|
||||
if (preferred.second != ID{0} && preferred.first > Seq{0})
|
||||
return (preferred.first >= minSeq) ? preferred.second : lcl.id();
|
||||
// Trusted validations exist, but stick with local preferred ledger if
|
||||
// preferred is in the past
|
||||
if (preferred)
|
||||
return (preferred->first >= minSeq) ? preferred->second : lcl.id();
|
||||
|
||||
// Otherwise, rely on peer ledgers
|
||||
auto it = std::max_element(
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
//==============================================================================
|
||||
#include <ripple/beast/unit_test.h>
|
||||
#include <ripple/consensus/LedgerTrie.h>
|
||||
#include <random>
|
||||
#include <test/csf/ledgers.h>
|
||||
#include <unordered_map>
|
||||
#include <random>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
@@ -29,7 +29,6 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
{
|
||||
beast::Journal j;
|
||||
|
||||
|
||||
void
|
||||
testInsert()
|
||||
{
|
||||
@@ -141,20 +140,19 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
{
|
||||
LedgerTrie<Ledger> t;
|
||||
LedgerHistoryHelper h;
|
||||
t.insert(h["ab"],4);
|
||||
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);
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +189,7 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
{
|
||||
LedgerTrie<Ledger> t;
|
||||
LedgerHistoryHelper h;
|
||||
t.insert(h["abc"],2);
|
||||
t.insert(h["abc"], 2);
|
||||
|
||||
BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
|
||||
BEAST_EXPECT(t.remove(h["abc"]));
|
||||
@@ -209,7 +207,6 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
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
|
||||
{
|
||||
@@ -288,17 +285,35 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
|
||||
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;
|
||||
using Seq = Ledger::Seq;
|
||||
|
||||
|
||||
LedgerTrie<Ledger> t;
|
||||
LedgerHistoryHelper h;
|
||||
BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
|
||||
@@ -339,7 +354,6 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
|
||||
BEAST_EXPECT(t.branchSupport(h["abc"]) == 0);
|
||||
BEAST_EXPECT(t.branchSupport(h["abe"]) == 1);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -348,18 +362,28 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
using namespace csf;
|
||||
using Seq = Ledger::Seq;
|
||||
// Empty
|
||||
{
|
||||
LedgerTrie<Ledger> t;
|
||||
BEAST_EXPECT(t.getPreferred(Seq{0}) == boost::none);
|
||||
BEAST_EXPECT(t.getPreferred(Seq{2}) == boost::none);
|
||||
}
|
||||
// Genesis support is NOT empty
|
||||
{
|
||||
LedgerTrie<Ledger> t;
|
||||
LedgerHistoryHelper h;
|
||||
BEAST_EXPECT(t.getPreferred(Seq{0}).id == h[""].id());
|
||||
BEAST_EXPECT(t.getPreferred(Seq{2}).id == h[""].id());
|
||||
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}) == boost::none);
|
||||
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());
|
||||
BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
|
||||
}
|
||||
// Single node smaller child support
|
||||
{
|
||||
@@ -367,17 +391,17 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
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());
|
||||
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());
|
||||
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
|
||||
{
|
||||
@@ -386,40 +410,40 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
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());
|
||||
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());
|
||||
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["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());
|
||||
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());
|
||||
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);
|
||||
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());
|
||||
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());
|
||||
BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
|
||||
}
|
||||
|
||||
// Tie-breaker not needed
|
||||
@@ -428,17 +452,17 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
LedgerHistoryHelper h;
|
||||
t.insert(h["abc"]);
|
||||
t.insert(h["abcd"]);
|
||||
t.insert(h["abce"],2);
|
||||
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());
|
||||
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());
|
||||
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
|
||||
@@ -446,11 +470,11 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
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());
|
||||
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
|
||||
@@ -458,25 +482,25 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
LedgerTrie<Ledger> t;
|
||||
LedgerHistoryHelper h;
|
||||
t.insert(h["abc"]);
|
||||
t.insert(h["abcde"],2);
|
||||
t.insert(h["abcfg"],2);
|
||||
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());
|
||||
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());
|
||||
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());
|
||||
BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abc"].id());
|
||||
}
|
||||
|
||||
// Changing largestSeq perspective changes preferred branch
|
||||
@@ -497,15 +521,15 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
t.insert(h["ab"]);
|
||||
t.insert(h["ac"]);
|
||||
t.insert(h["acf"]);
|
||||
t.insert(h["abde"],2);
|
||||
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());
|
||||
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());
|
||||
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
|
||||
@@ -521,11 +545,11 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
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());
|
||||
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
|
||||
@@ -540,11 +564,11 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
*/
|
||||
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());
|
||||
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
|
||||
@@ -559,15 +583,12 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
*/
|
||||
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());
|
||||
|
||||
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
|
||||
@@ -613,22 +634,22 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
// Ledgers have sequence 1,2,3,4
|
||||
std::uint32_t const depth = 4;
|
||||
// Each ledger has 4 possible children
|
||||
std::uint32_t const width = 4;
|
||||
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, depth-1);
|
||||
std::uniform_int_distribution<> widthDist(0, width-1);
|
||||
std::mt19937 gen{42};
|
||||
std::uniform_int_distribution<> depthDist(0, depth - 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)
|
||||
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)
|
||||
for (char d = 0; d < depth; ++d)
|
||||
{
|
||||
char a = offset + widthDist(gen);
|
||||
curr += a;
|
||||
@@ -636,11 +657,11 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
// 50-50 to add remove
|
||||
if(flip(gen) == 0)
|
||||
if (flip(gen) == 0)
|
||||
t.insert(h[curr]);
|
||||
else
|
||||
t.remove(h[curr]);
|
||||
if(!BEAST_EXPECT(t.checkInvariants()))
|
||||
if (!BEAST_EXPECT(t.checkInvariants()))
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -650,6 +671,7 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
{
|
||||
testInsert();
|
||||
testRemove();
|
||||
testEmpty();
|
||||
testSupport();
|
||||
testGetPreferred();
|
||||
testRootRelated();
|
||||
|
||||
@@ -58,9 +58,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
boost::optional<std::uint32_t> loadFee_;
|
||||
|
||||
public:
|
||||
Node(PeerID nodeID, clock_type const& c)
|
||||
: c_(c)
|
||||
, nodeID_(nodeID)
|
||||
Node(PeerID nodeID, clock_type const& c) : c_(c), nodeID_(nodeID)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -292,7 +290,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
}
|
||||
};
|
||||
|
||||
Ledger const genesisLedger{Ledger::MakeGenesis{}};
|
||||
Ledger const genesisLedger{Ledger::MakeGenesis{}};
|
||||
|
||||
void
|
||||
testAddValidation()
|
||||
@@ -349,8 +347,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(
|
||||
ValStatus::badSeq == harness.add(n.validate(ledgerAB)));
|
||||
// Cannot send the same partial validation sequence
|
||||
BEAST_EXPECT(
|
||||
ValStatus::badSeq == harness.add(n.partial(ledgerAB)));
|
||||
BEAST_EXPECT(ValStatus::badSeq == harness.add(n.partial(ledgerAB)));
|
||||
|
||||
// Now trusts the newest ledger too
|
||||
harness.clock().advance(1s);
|
||||
@@ -425,9 +422,8 @@ class Validations_test : public beast::unit_test::suite
|
||||
TestHarness harness(h.oracle);
|
||||
Node n = harness.makeNode();
|
||||
|
||||
auto process = [&](Ledger & lgr)
|
||||
{
|
||||
if(doFull)
|
||||
auto process = [&](Ledger& lgr) {
|
||||
if (doFull)
|
||||
return harness.add(n.validate(lgr));
|
||||
return harness.add(n.partial(lgr));
|
||||
};
|
||||
@@ -458,7 +454,6 @@ class Validations_test : public beast::unit_test::suite
|
||||
Ledger ledgerA = h["a"];
|
||||
Ledger ledgerAB = h["ab"];
|
||||
|
||||
|
||||
using Trigger = std::function<void(TestValidations&)>;
|
||||
|
||||
std::vector<Trigger> triggers = {
|
||||
@@ -492,8 +487,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(
|
||||
harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 0);
|
||||
BEAST_EXPECT(
|
||||
harness.vals().getPreferred(genesisLedger) ==
|
||||
std::make_pair(Ledger::Seq{0}, Ledger::ID{0}));
|
||||
harness.vals().getPreferred(genesisLedger) == boost::none);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,8 +605,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
ValStatus::current == harness.add(node.validate(ledgerA)));
|
||||
|
||||
{
|
||||
hash_set<PeerID> const expectedKeys = {a.nodeID(),
|
||||
b.nodeID()};
|
||||
hash_set<PeerID> const expectedKeys = {a.nodeID(), b.nodeID()};
|
||||
BEAST_EXPECT(harness.vals().getCurrentNodeIDs() == expectedKeys);
|
||||
}
|
||||
|
||||
@@ -627,8 +620,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
ValStatus::current == harness.add(node.partial(ledgerAC)));
|
||||
|
||||
{
|
||||
hash_set<PeerID> const expectedKeys = {a.nodeID(),
|
||||
b.nodeID()};
|
||||
hash_set<PeerID> const expectedKeys = {a.nodeID(), b.nodeID()};
|
||||
BEAST_EXPECT(harness.vals().getCurrentNodeIDs() == expectedKeys);
|
||||
}
|
||||
|
||||
@@ -695,7 +687,6 @@ class Validations_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(
|
||||
sorted(harness.vals().fees(id, baseFee)) ==
|
||||
sorted(expectedFees));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -836,8 +827,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
};
|
||||
|
||||
// Empty (no ledgers)
|
||||
BEAST_EXPECT(
|
||||
harness.vals().getPreferred(ledgerA) == pref(genesisLedger));
|
||||
BEAST_EXPECT(harness.vals().getPreferred(ledgerA) == boost::none);
|
||||
|
||||
// Single ledger
|
||||
BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerB)));
|
||||
@@ -1069,8 +1059,12 @@ class Validations_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(
|
||||
vals.getNodesAfter(this->genesisLedger, genesisLedger.id()) ==
|
||||
trustedVals.size());
|
||||
BEAST_EXPECT(
|
||||
vals.getPreferred(this->genesisLedger).second == testID);
|
||||
if (trustedVals.empty())
|
||||
BEAST_EXPECT(
|
||||
vals.getPreferred(this->genesisLedger) == boost::none);
|
||||
else
|
||||
BEAST_EXPECT(
|
||||
vals.getPreferred(this->genesisLedger)->second == testID);
|
||||
BEAST_EXPECT(vals.getTrustedForLedger(testID) == trustedVals);
|
||||
BEAST_EXPECT(
|
||||
vals.numTrustedForLedger(testID) == trustedVals.size());
|
||||
@@ -1127,7 +1121,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
auto& vals = harness.vals();
|
||||
BEAST_EXPECT(vals.currentTrusted() == trustedVals);
|
||||
BEAST_EXPECT(
|
||||
vals.getPreferred(genesisLedger).second == v.ledgerID());
|
||||
vals.getPreferred(genesisLedger)->second == v.ledgerID());
|
||||
BEAST_EXPECT(
|
||||
vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0);
|
||||
|
||||
@@ -1136,8 +1130,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
// make acquiring ledger available
|
||||
h["ab"];
|
||||
BEAST_EXPECT(vals.currentTrusted() == trustedVals);
|
||||
BEAST_EXPECT(
|
||||
vals.getPreferred(genesisLedger).second == genesisLedger.id());
|
||||
BEAST_EXPECT(vals.getPreferred(genesisLedger) == boost::none);
|
||||
BEAST_EXPECT(
|
||||
vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user