1#include <xrpl/consensus/Validations.h>
3#include <xrpl/basics/UnorderedContainers.h>
4#include <xrpl/basics/chrono.h>
5#include <xrpl/basics/tagged_integer.h>
6#include <xrpl/beast/clock/abstract_clock.h>
7#include <xrpl/beast/clock/manual_clock.h>
8#include <xrpl/beast/utility/Journal.h>
10#include <csf/Validation.h>
11#include <csf/ledgers.h>
12#include <gtest/gtest.h>
13#include <helpers/TestSink.h>
33template <
class Val
idationStore>
35expireValidations(ValidationStore& validations)
38 validations.expire(j);
46toNetClock(clock_type
const& c)
66 Node(
PeerID nodeID, clock_type
const& c) : c_(c), nodeID_(nodeID)
114 return toNetClock(c_);
128 id, seq, now() + signOffset, now() + seenOffset, currKey(), nodeID_, full, loadFee_};
137 return validate(ledger.
id(), ledger.
seq(), signOffset, seenOffset,
true);
141 validate(
Ledger ledger)
const
148 partial(
Ledger ledger)
const
179 Adaptor(clock_type& c,
LedgerOracle& o) : c_{c}, oracle_{o}
186 return toNetClock(c_);
192 return oracle_.
lookup(
id);
209 explicit TestHarness(
LedgerOracle& o) : tv_(p_, clock_, clock_, o)
216 return tv_.add(v.
nodeID(), v);
228 return Node(nextNodeId_++, clock_);
248TEST(ValidationsTest, add_validation)
250 using namespace std::chrono_literals;
252 SCOPED_TRACE(
"Add validation");
254 Ledger const ledgerA = h[
"a"];
255 Ledger ledgerAB = h[
"ab"];
256 Ledger ledgerAZ = h[
"az"];
257 Ledger ledgerABC = h[
"abc"];
258 Ledger const ledgerABCD = h[
"abcd"];
259 Ledger const ledgerABCDE = h[
"abcde"];
262 TestHarness harness(h.
oracle);
263 Node n = harness.makeNode();
265 auto const v = n.validate(ledgerA);
274 harness.clock().advance(1s);
281 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerAB.
id()) == 1);
282 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerABC.
id()) == 0);
287 harness.clock().advance(1s);
295 harness.clock().advance(1s);
297 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerAB.
id()) == 1);
298 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerABC.
id()) == 1);
302 harness.clock().advance(2s);
303 auto const valABCDE = n.validate(ledgerABCDE);
305 harness.clock().advance(4s);
306 auto const valABCD = n.validate(ledgerABCD);
316 TestHarness harness(h.
oracle);
317 Node
const n = harness.makeNode();
323 EXPECT_TRUE(
ValStatus::Stale == harness.add(n.validate(ledgerAB, -1s, -1s)));
332 TestHarness harness(h.
oracle);
333 Node
const n = harness.makeNode();
337 harness.add(n.validate(ledgerA, -harness.parms().validationCurrentEarly, 0s)));
341 harness.add(n.validate(ledgerA, harness.parms().validationCurrentWall, 0s)));
345 harness.add(n.validate(ledgerA, 0s, harness.parms().validationCurrentLocal)));
351 for (
bool doFull : {
true,
false})
353 TestHarness harness(h.
oracle);
354 Node n = harness.makeNode();
356 auto process = [&](
Ledger& lgr) {
358 return harness.add(n.validate(lgr));
359 return harness.add(n.partial(lgr));
363 harness.clock().advance(1s);
364 EXPECT_TRUE(ledgerAB.
seq() < ledgerABC.
seq());
370 harness.clock().advance(harness.parms().validationSetExpires + 1ms);
378 SCOPED_TRACE(
"Stale validation");
384 Ledger const ledgerAB = h[
"ab"];
389 [&](TestValidations& vals) { vals.currentTrusted(); },
390 [&](TestValidations& vals) { vals.getCurrentNodeIDs(); },
391 [&](TestValidations& vals) { vals.getPreferred(kGenesisLedger); },
392 [&](TestValidations& vals) { vals.getNodesAfter(ledgerA, ledgerA.
id()); }};
393 for (Trigger
const& trigger : triggers)
395 TestHarness harness(h.
oracle);
396 Node
const n = harness.makeNode();
399 trigger(harness.vals());
400 EXPECT_TRUE(harness.vals().getNodesAfter(ledgerA, ledgerA.
id()) == 1);
402 harness.vals().getPreferred(kGenesisLedger) ==
404 harness.clock().advance(harness.parms().validationCurrentLocal);
407 trigger(harness.vals());
409 EXPECT_TRUE(harness.vals().getNodesAfter(ledgerA, ledgerA.
id()) == 0);
410 EXPECT_TRUE(harness.vals().getPreferred(kGenesisLedger) == std::nullopt);
414TEST(ValidationsTest, get_nodes_after)
420 using namespace std::chrono_literals;
421 SCOPED_TRACE(
"Get nodes after");
424 Ledger const ledgerA = h[
"a"];
425 Ledger const ledgerAB = h[
"ab"];
426 Ledger const ledgerABC = h[
"abc"];
427 Ledger const ledgerAD = h[
"ad"];
429 TestHarness harness(h.
oracle);
430 Node
const trustedNode1 = harness.makeNode();
431 Node
const trustedNode2 = harness.makeNode();
432 Node
const trustedNode3 = harness.makeNode();
434 Node notTrustedNode = harness.makeNode();
435 notTrustedNode.untrust();
443 for (
Ledger const& ledger : {ledgerA, ledgerAB, ledgerABC, ledgerAD})
444 EXPECT_TRUE(harness.vals().getNodesAfter(ledger, ledger.id()) == 0);
446 harness.clock().advance(5s);
453 EXPECT_TRUE(harness.vals().getNodesAfter(ledgerA, ledgerA.
id()) == 3);
454 EXPECT_TRUE(harness.vals().getNodesAfter(ledgerAB, ledgerAB.
id()) == 2);
455 EXPECT_TRUE(harness.vals().getNodesAfter(ledgerABC, ledgerABC.
id()) == 0);
456 EXPECT_TRUE(harness.vals().getNodesAfter(ledgerAD, ledgerAD.
id()) == 0);
459 EXPECT_TRUE(harness.vals().getNodesAfter(ledgerAD, ledgerA.
id()) == 1);
460 EXPECT_TRUE(harness.vals().getNodesAfter(ledgerAD, ledgerAB.
id()) == 2);
463TEST(ValidationsTest, current_trusted)
465 using namespace std::chrono_literals;
466 SCOPED_TRACE(
"Current trusted validations");
469 Ledger const ledgerA = h[
"a"];
470 Ledger const ledgerB = h[
"b"];
471 Ledger const ledgerAC = h[
"ac"];
473 TestHarness harness(h.
oracle);
474 Node
const a = harness.makeNode();
475 Node b = harness.makeNode();
482 EXPECT_TRUE(harness.vals().currentTrusted().size() == 1);
483 EXPECT_TRUE(harness.vals().currentTrusted()[0].ledgerID() == ledgerA.
id());
484 EXPECT_TRUE(harness.vals().currentTrusted()[0].seq() == ledgerA.
seq());
486 harness.clock().advance(3s);
488 for (
auto const& node : {a, b})
492 EXPECT_TRUE(harness.vals().currentTrusted().size() == 1);
493 EXPECT_TRUE(harness.vals().currentTrusted()[0].ledgerID() == ledgerAC.
id());
494 EXPECT_TRUE(harness.vals().currentTrusted()[0].seq() == ledgerAC.
seq());
497 harness.clock().advance(harness.parms().validationCurrentLocal);
498 EXPECT_TRUE(harness.vals().currentTrusted().empty());
501TEST(ValidationsTest, get_current_public_keys)
503 using namespace std::chrono_literals;
504 SCOPED_TRACE(
"Current public keys");
507 Ledger const ledgerA = h[
"a"];
508 Ledger const ledgerAC = h[
"ac"];
510 TestHarness harness(h.
oracle);
511 Node a = harness.makeNode(), b = harness.makeNode();
514 for (
auto const& node : {a, b})
519 EXPECT_TRUE(harness.vals().getCurrentNodeIDs() == expectedKeys);
522 harness.clock().advance(3s);
528 for (
auto const& node : {a, b})
533 EXPECT_TRUE(harness.vals().getCurrentNodeIDs() == expectedKeys);
537 harness.clock().advance(harness.parms().validationCurrentLocal);
538 EXPECT_TRUE(harness.vals().getCurrentNodeIDs().empty());
541TEST(ValidationsTest, trusted_by_ledger_functions)
544 using namespace std::chrono_literals;
545 SCOPED_TRACE(
"By ledger functions");
554 TestHarness harness(h.
oracle);
556 Node a = harness.makeNode(), b = harness.makeNode(), c = harness.makeNode(),
557 d = harness.makeNode(), e = harness.makeNode();
570 auto sorted = [](
auto vec) {
574 auto compare = [&]() {
575 for (
auto& it : trustedValidations)
577 auto const&
id = it.first.first;
578 auto const& seq = it.first.second;
579 auto const& expectedValidations = it.second;
581 EXPECT_TRUE(harness.vals().numTrustedForLedger(
id) == expectedValidations.size());
583 sorted(harness.vals().getTrustedForLedger(
id, seq)) == sorted(expectedValidations));
587 expectedFees.
reserve(expectedValidations.size());
588 for (
auto const& val : expectedValidations)
590 expectedFees.
push_back(val.loadFee().value_or(baseFee));
593 EXPECT_TRUE(sorted(harness.vals().fees(
id, baseFee)) == sorted(expectedFees));
598 Ledger const ledgerA = h[
"a"];
599 Ledger const ledgerB = h[
"b"];
600 Ledger const ledgerAC = h[
"ac"];
606 for (
auto const& node : {a, b, c})
608 auto const val = node.validate(ledgerA);
611 trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(val);
615 auto const val = d.validate(ledgerB);
617 trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(val);
624 harness.clock().advance(5s);
626 for (
auto const& node : {a, b, c})
628 auto const val = node.validate(ledgerAC);
631 trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(val);
649 SCOPED_TRACE(
"Expire validations");
651 TestHarness harness(h.
oracle);
652 Node
const a = harness.makeNode();
657 Ledger const ledgerA = h[
"a"];
659 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerA.
id()) == 1);
660 expireValidations(harness.vals());
661 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerA.
id()) == 1);
662 harness.clock().advance(harness.parms().validationSetExpires);
663 expireValidations(harness.vals());
664 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerA.
id()) == 0);
667 Ledger const ledgerB = h[
"ab"];
669 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerB.
id()) == 1);
670 harness.vals().setSeqToKeep(ledgerB.
seq(), ledgerB.
seq() + kOne);
671 harness.clock().advance(harness.parms().validationSetExpires);
672 expireValidations(harness.vals());
673 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerB.
id()) == 1);
675 harness.vals().setSeqToKeep(ledgerB.
seq() + kOne, ledgerB.
seq() + kTwo);
678 harness.parms().validationSetExpires / harness.parms().validationFRESHNESS + 1;
679 for (
int i = 0; i < loops; ++i)
681 harness.clock().advance(harness.parms().validationFRESHNESS);
682 expireValidations(harness.vals());
684 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerB.
id()) == 0);
687 Ledger const ledgerC = h[
"abc"];
689 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerC.
id()) == 1);
690 harness.vals().setSeqToKeep(ledgerC.
seq() - kOne, ledgerC.
seq());
691 harness.clock().advance(harness.parms().validationSetExpires);
692 expireValidations(harness.vals());
693 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerC.
id()) == 0);
699 using namespace std::chrono_literals;
700 SCOPED_TRACE(
"Flush validations");
703 TestHarness harness(h.
oracle);
704 Node
const trustedNode1 = harness.makeNode();
705 Node
const trustedNode2 = harness.makeNode();
706 Node notTrustedNode = harness.makeNode();
707 notTrustedNode.untrust();
709 Ledger const ledgerA = h[
"a"];
710 Ledger const ledgerAB = h[
"ab"];
713 for (
auto const& node : {trustedNode1, trustedNode2, notTrustedNode})
715 auto const val = node.validate(ledgerA);
717 expected.
emplace(node.nodeID(), val);
722 harness.clock().advance(1s);
723 auto newVal = trustedNode1.validate(ledgerAB);
725 expected.
find(trustedNode1.nodeID())->second = newVal;
728TEST(ValidationsTest, get_preferred_ledger)
730 using namespace std::chrono_literals;
731 SCOPED_TRACE(
"Preferred Ledger");
734 TestHarness harness(h.
oracle);
735 Node
const trustedNode1 = harness.makeNode();
736 Node
const trustedNode2 = harness.makeNode();
737 Node
const trustedNode3 = harness.makeNode();
739 Node notTrustedNode = harness.makeNode();
740 notTrustedNode.untrust();
742 Ledger const ledgerA = h[
"a"];
743 Ledger const ledgerB = h[
"b"];
744 Ledger const ledgerAC = h[
"ac"];
745 Ledger const ledgerACD = h[
"acd"];
752 EXPECT_TRUE(harness.vals().getPreferred(ledgerA) == std::nullopt);
756 EXPECT_TRUE(harness.vals().getPreferred(ledgerA) == pref(ledgerB));
757 EXPECT_TRUE(harness.vals().getPreferred(ledgerB) == pref(ledgerB));
760 EXPECT_TRUE(harness.vals().getPreferred(ledgerA,
Seq{10}) == ledgerA.
id());
766 EXPECT_TRUE(ledgerB.
id() > ledgerA.
id());
767 EXPECT_TRUE(harness.vals().getPreferred(ledgerA) == pref(ledgerB));
768 EXPECT_TRUE(harness.vals().getPreferred(ledgerB) == pref(ledgerB));
772 EXPECT_TRUE(harness.vals().getPreferred(ledgerA) == pref(ledgerA));
773 EXPECT_TRUE(harness.vals().getPreferred(ledgerB) == pref(ledgerA));
775 harness.clock().advance(5s);
778 for (
auto const& node : {trustedNode1, trustedNode2, notTrustedNode, trustedNode3})
781 EXPECT_TRUE(harness.vals().getPreferred(ledgerA) == pref(ledgerA));
783 EXPECT_TRUE(harness.vals().getPreferred(ledgerB) == pref(ledgerAC));
785 EXPECT_TRUE(harness.vals().getPreferred(ledgerACD) == pref(ledgerACD));
788 harness.clock().advance(5s);
789 for (
auto const& node : {trustedNode1, trustedNode2, notTrustedNode, trustedNode3})
791 for (
auto const& ledger : {ledgerA, ledgerB, ledgerACD})
792 EXPECT_TRUE(harness.vals().getPreferred(ledger) == pref(ledgerACD));
795TEST(ValidationsTest, get_preferred_lcl)
797 using namespace std::chrono_literals;
798 SCOPED_TRACE(
"Get preferred LCL");
801 TestHarness harness(h.
oracle);
802 Node
const a = harness.makeNode();
804 Ledger const ledgerA = h[
"a"];
805 Ledger const ledgerB = h[
"b"];
806 Ledger const ledgerC = h[
"c"];
814 EXPECT_TRUE(harness.vals().getPreferredLCL(ledgerA,
Seq{0}, peerCounts) == ledgerA.
id());
816 ++peerCounts[ledgerB.
id()];
819 EXPECT_TRUE(harness.vals().getPreferredLCL(ledgerA,
Seq{0}, peerCounts) == ledgerB.
id());
821 ++peerCounts[ledgerC.
id()];
823 EXPECT_TRUE(ledgerC.
id() > ledgerB.
id());
825 EXPECT_TRUE(harness.vals().getPreferredLCL(ledgerA,
Seq{0}, peerCounts) == ledgerC.
id());
827 peerCounts[ledgerC.
id()] += 1000;
831 EXPECT_TRUE(harness.vals().getPreferredLCL(ledgerA,
Seq{0}, peerCounts) == ledgerA.
id());
832 EXPECT_TRUE(harness.vals().getPreferredLCL(ledgerB,
Seq{0}, peerCounts) == ledgerA.
id());
833 EXPECT_TRUE(harness.vals().getPreferredLCL(ledgerC,
Seq{0}, peerCounts) == ledgerA.
id());
837 EXPECT_TRUE(harness.vals().getPreferredLCL(ledgerB,
Seq{2}, peerCounts) == ledgerB.
id());
840TEST(ValidationsTest, acquire_validated_ledger)
842 using namespace std::chrono_literals;
843 SCOPED_TRACE(
"Acquire validated ledger");
846 TestHarness harness(h.
oracle);
847 Node
const a = harness.makeNode();
848 Node
const b = harness.makeNode();
854 Validation const val = a.validate(ID{2},
Seq{2}, 0s, 0s,
true);
858 EXPECT_TRUE(harness.vals().numTrustedForLedger(ID{2}) == 1);
860 EXPECT_TRUE(harness.vals().getNodesAfter(kGenesisLedger, ID{0}) == 0);
863 EXPECT_TRUE(harness.vals().getPreferred(kGenesisLedger) ==
std::make_pair(
Seq{2}, ID{2}));
868 EXPECT_TRUE(harness.vals().getPreferred(kGenesisLedger) ==
std::make_pair(
Seq{2}, ID{3}));
871 Ledger const ledgerAB = h[
"ab"];
873 EXPECT_TRUE(harness.vals().getNodesAfter(kGenesisLedger, ID{0}) == 1);
876 harness.clock().advance(5s);
877 Validation const val2 = a.validate(ID{4},
Seq{4}, 0s, 0s,
true);
879 EXPECT_TRUE(harness.vals().numTrustedForLedger(ID{4}) == 1);
881 harness.vals().getPreferred(kGenesisLedger) ==
885 Validation const val3 = b.validate(ID{4},
Seq{4}, 0s, 0s,
true);
887 EXPECT_TRUE(harness.vals().numTrustedForLedger(ID{4}) == 2);
889 harness.vals().getPreferred(kGenesisLedger) ==
893 harness.clock().advance(5s);
894 Ledger const ledgerABCDE = h[
"abcde"];
898 harness.vals().getPreferred(kGenesisLedger) ==
902TEST(ValidationsTest, num_trusted_for_ledger)
904 SCOPED_TRACE(
"NumTrustedForLedger");
906 TestHarness harness(h.
oracle);
907 Node
const a = harness.makeNode();
908 Node
const b = harness.makeNode();
909 Ledger const ledgerA = h[
"a"];
912 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerA.
id()) == 0);
915 EXPECT_TRUE(harness.vals().numTrustedForLedger(ledgerA.
id()) == 1);
918TEST(ValidationsTest, seq_enforcer)
920 SCOPED_TRACE(
"SeqEnforcer");
929 EXPECT_TRUE(enforcer(
clock.now(),
Seq{1}, p));
930 EXPECT_TRUE(enforcer(
clock.now(),
Seq{10}, p));
931 EXPECT_TRUE(!enforcer(
clock.now(),
Seq{5}, p));
932 EXPECT_TRUE(!enforcer(
clock.now(),
Seq{9}, p));
934 EXPECT_TRUE(!enforcer(
clock.now(),
Seq{1}, p));
936 EXPECT_TRUE(enforcer(
clock.now(),
Seq{1}, p));
939TEST(ValidationsTest, trust_changed)
941 SCOPED_TRACE(
"TrustChanged");
944 auto checker = [&](TestValidations& vals,
948 trustedVals.empty() ? kGenesisLedger.id() : trustedVals[0].ledgerID();
950 trustedVals.empty() ? kGenesisLedger.seq() : trustedVals[0].seq();
951 EXPECT_TRUE(vals.currentTrusted() == trustedVals);
952 EXPECT_TRUE(vals.getCurrentNodeIDs() == listed);
953 EXPECT_TRUE(vals.getNodesAfter(kGenesisLedger, kGenesisLedger.id()) == trustedVals.size());
954 if (trustedVals.empty())
956 EXPECT_TRUE(vals.getPreferred(kGenesisLedger) == std::nullopt);
960 EXPECT_TRUE(vals.getPreferred(kGenesisLedger)->second == testID);
962 EXPECT_TRUE(vals.getTrustedForLedger(testID, testSeq) == trustedVals);
963 EXPECT_TRUE(vals.numTrustedForLedger(testID) == trustedVals.size());
969 TestHarness harness(h.
oracle);
970 Node
const a = harness.makeNode();
971 Ledger const ledgerAB = h[
"ab"];
977 checker(harness.vals(), listed, trustedVals);
980 harness.vals().trustChanged({}, {a.nodeID()});
981 checker(harness.vals(), listed, trustedVals);
987 TestHarness harness(h.
oracle);
988 Node a = harness.makeNode();
990 Ledger const ledgerAB = h[
"ab"];
996 checker(harness.vals(), listed, trustedVals);
998 trustedVals.push_back(v);
999 harness.vals().trustChanged({a.nodeID()}, {});
1000 checker(harness.vals(), listed, trustedVals);
1006 TestHarness harness(h.
oracle);
1007 Node
const a = harness.makeNode();
1013 auto& vals = harness.vals();
1014 EXPECT_TRUE(vals.currentTrusted() == trustedVals);
1017 EXPECT_TRUE(vals.getPreferred(kGenesisLedger)->second == v.
ledgerID());
1018 EXPECT_TRUE(vals.getNodesAfter(kGenesisLedger, kGenesisLedger.id()) == 0);
1020 trustedVals.clear();
1021 harness.vals().trustChanged({}, {a.nodeID()});
1024 EXPECT_TRUE(vals.currentTrusted() == trustedVals);
1025 EXPECT_TRUE(vals.getPreferred(kGenesisLedger) == std::nullopt);
1026 EXPECT_TRUE(vals.getNodesAfter(kGenesisLedger, kGenesisLedger.id()) == 0);
Abstract interface to a clock.
A generic endpoint for log messages.
Manual clock implementation.
std::chrono::time_point< NetClock > time_point
std::chrono::duration< rep, period > duration
Enforce validation increasing sequence requirement.
static TestSink & instance()
Maintains current and recent ledger validations.
Oracle maintaining unique ledgers for a simulation.
std::optional< Ledger > lookup(Ledger::ID const &id) const
Find the ledger with the given ID.
A ledger is a set of observed transactions and a sequence number identifying the ledger.
TaggedInteger< std::uint32_t, IdTag > ID
TaggedInteger< std::uint32_t, SeqTag > Seq
Validation of a specific ledger by a specific Peer.
PeerID const & nodeID() const
Ledger::ID ledgerID() const
T duration_cast(T... args)
TEST(ValidationsTest, add_validation)
TaggedInteger< std::uint32_t, PeerIDTag > PeerID
std::pair< PeerID, std::uint32_t > PeerKey
The current key of a peer.
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
std::unordered_set< Value, Hash, Pred, Allocator > hash_set
ValStatus
Status of validation we received.
@ Current
This was a new validation and was added.
@ BadSeq
A validation violates the increasing seq requirement.
@ Conflicting
Multiple validations by a validator for different ledgers.
@ Stale
Not current or was older than current from this node.
std::unordered_map< Key, Value, Hash, Pred, Allocator > hash_map
Timing parameters to control validation staleness and expiration.
std::chrono::seconds validationSetExpires
Duration a set of validations for a given ledger hash remain valid.
Helper for writing unit tests with controlled ledger histories.
Set the sequence number on a JTx.