rippled
Loading...
Searching...
No Matches
Validations_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2017 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/csf/Validation.h>
21#include <test/unit_test/SuiteJournal.h>
22
23#include <xrpld/consensus/Validations.h>
24
25#include <xrpl/basics/tagged_integer.h>
26#include <xrpl/beast/clock/manual_clock.h>
27#include <xrpl/beast/unit_test.h>
28
29#include <vector>
30
31namespace ripple {
32namespace test {
33namespace csf {
35{
37
38 // Helper to convert steady_clock to a reasonable NetClock
39 // This allows a single manual clock in the unit tests
42 {
43 // We don't care about the actual epochs, but do want the
44 // generated NetClock time to be well past its epoch to ensure
45 // any subtractions are positive
46 using namespace std::chrono;
47 return NetClock::time_point(duration_cast<NetClock::duration>(
48 c.now().time_since_epoch() + 86400s));
49 }
50
51 // Represents a node that can issue validations
52 class Node
53 {
54 clock_type const& c_;
56 bool trusted_ = true;
59
60 public:
62 {
63 }
64
65 void
67 {
68 trusted_ = false;
69 }
70
71 void
73 {
74 trusted_ = true;
75 }
76
77 void
82
83 PeerID
84 nodeID() const
85 {
86 return nodeID_;
87 }
88
89 void
91 {
92 signIdx_++;
93 }
94
96 currKey() const
97 {
99 }
100
101 PeerKey
102 masterKey() const
103 {
104 return std::make_pair(nodeID_, 0);
105 }
107 now() const
108 {
109 return toNetClock(c_);
110 }
111
112 // Issue a new validation with given sequence number and id and
113 // with signing and seen times offset from the common clock
116 Ledger::ID id,
118 NetClock::duration signOffset,
119 NetClock::duration seenOffset,
120 bool full) const
121 {
122 Validation v{
123 id,
124 seq,
125 now() + signOffset,
126 now() + seenOffset,
127 currKey(),
128 nodeID_,
129 full,
130 loadFee_};
131 if (trusted_)
132 v.setTrusted();
133 return v;
134 }
135
138 Ledger ledger,
139 NetClock::duration signOffset,
140 NetClock::duration seenOffset) const
141 {
142 return validate(
143 ledger.id(), ledger.seq(), signOffset, seenOffset, true);
144 }
145
147 validate(Ledger ledger) const
148 {
149 return validate(
150 ledger.id(),
151 ledger.seq(),
154 true);
155 }
156
158 partial(Ledger ledger) const
159 {
160 return validate(
161 ledger.id(),
162 ledger.seq(),
165 false);
166 }
167 };
168
169 // Generic Validations adaptor
171 {
174
175 public:
176 // Non-locking mutex to avoid locks in generic Validations
177 struct Mutex
178 {
179 void
181 {
182 }
183
184 void
186 {
187 }
188 };
189
192
194 {
195 }
196
198 now() const
199 {
200 return toNetClock(c_);
201 }
202
205 {
206 return oracle_.lookup(id);
207 }
208 };
209
210 // Specialize generic Validations using the above types
212
213 // Gather the dependencies of TestValidations in a single class and provide
214 // accessors for simplifying test logic
216 {
221
222 public:
224 {
225 }
226
228 add(Validation const& v)
229 {
230 return tv_.add(v.nodeID(), v);
231 }
232
235 {
236 return tv_;
237 }
238
239 Node
241 {
242 return Node(nextNodeId_++, clock_);
243 }
244
246 parms() const
247 {
248 return p_;
249 }
250
251 auto&
253 {
254 return clock_;
255 }
256 };
257
259
260 void
262 {
263 using namespace std::chrono_literals;
264
265 testcase("Add validation");
267 Ledger ledgerA = h["a"];
268 Ledger ledgerAB = h["ab"];
269 Ledger ledgerAZ = h["az"];
270 Ledger ledgerABC = h["abc"];
271 Ledger ledgerABCD = h["abcd"];
272 Ledger ledgerABCDE = h["abcde"];
273
274 {
275 TestHarness harness(h.oracle);
276 Node n = harness.makeNode();
277
278 auto const v = n.validate(ledgerA);
279
280 // Add a current validation
281 BEAST_EXPECT(ValStatus::current == harness.add(v));
282
283 // Re-adding violates the increasing seq requirement for full
284 // validations
285 BEAST_EXPECT(ValStatus::badSeq == harness.add(v));
286
287 harness.clock().advance(1s);
288
289 BEAST_EXPECT(
290 ValStatus::current == harness.add(n.validate(ledgerAB)));
291
292 // Test the node changing signing key
293
294 // Confirm old ledger on hand, but not new ledger
295 BEAST_EXPECT(
296 harness.vals().numTrustedForLedger(ledgerAB.id()) == 1);
297 BEAST_EXPECT(
298 harness.vals().numTrustedForLedger(ledgerABC.id()) == 0);
299
300 // Rotate signing keys
301 n.advanceKey();
302
303 harness.clock().advance(1s);
304
305 // Cannot re-do the same full validation sequence
306 BEAST_EXPECT(
307 ValStatus::conflicting == harness.add(n.validate(ledgerAB)));
308 // Cannot send the same partial validation sequence
309 BEAST_EXPECT(
310 ValStatus::conflicting == harness.add(n.partial(ledgerAB)));
311
312 // Now trusts the newest ledger too
313 harness.clock().advance(1s);
314 BEAST_EXPECT(
315 ValStatus::current == harness.add(n.validate(ledgerABC)));
316 BEAST_EXPECT(
317 harness.vals().numTrustedForLedger(ledgerAB.id()) == 1);
318 BEAST_EXPECT(
319 harness.vals().numTrustedForLedger(ledgerABC.id()) == 1);
320
321 // Processing validations out of order should ignore the older
322 // validation
323 harness.clock().advance(2s);
324 auto const valABCDE = n.validate(ledgerABCDE);
325
326 harness.clock().advance(4s);
327 auto const valABCD = n.validate(ledgerABCD);
328
329 BEAST_EXPECT(ValStatus::current == harness.add(valABCD));
330
331 BEAST_EXPECT(ValStatus::stale == harness.add(valABCDE));
332 }
333
334 {
335 // Process validations out of order with shifted times
336
337 TestHarness harness(h.oracle);
338 Node n = harness.makeNode();
339
340 // Establish a new current validation
341 BEAST_EXPECT(
342 ValStatus::current == harness.add(n.validate(ledgerA)));
343
344 // Process a validation that has "later" seq but early sign time
345 BEAST_EXPECT(
347 harness.add(n.validate(ledgerAB, -1s, -1s)));
348
349 // Process a validation that has a later seq and later sign
350 // time
351 BEAST_EXPECT(
353 harness.add(n.validate(ledgerABC, 1s, 1s)));
354 }
355
356 {
357 // Test stale on arrival validations
358 TestHarness harness(h.oracle);
359 Node n = harness.makeNode();
360
361 BEAST_EXPECT(
363 harness.add(n.validate(
364 ledgerA, -harness.parms().validationCURRENT_EARLY, 0s)));
365
366 BEAST_EXPECT(
368 harness.add(n.validate(
369 ledgerA, harness.parms().validationCURRENT_WALL, 0s)));
370
371 BEAST_EXPECT(
373 harness.add(n.validate(
374 ledgerA, 0s, harness.parms().validationCURRENT_LOCAL)));
375 }
376
377 {
378 // Test that full or partials cannot be sent for older sequence
379 // numbers, unless time-out has happened
380 for (bool doFull : {true, false})
381 {
382 TestHarness harness(h.oracle);
383 Node n = harness.makeNode();
384
385 auto process = [&](Ledger& lgr) {
386 if (doFull)
387 return harness.add(n.validate(lgr));
388 return harness.add(n.partial(lgr));
389 };
390
391 BEAST_EXPECT(ValStatus::current == process(ledgerABC));
392 harness.clock().advance(1s);
393 BEAST_EXPECT(ledgerAB.seq() < ledgerABC.seq());
394 BEAST_EXPECT(ValStatus::badSeq == process(ledgerAB));
395
396 // If we advance far enough for AB to expire, we can fully
397 // validate or partially validate that sequence number again
398 BEAST_EXPECT(ValStatus::conflicting == process(ledgerAZ));
399 harness.clock().advance(
400 harness.parms().validationSET_EXPIRES + 1ms);
401 BEAST_EXPECT(ValStatus::current == process(ledgerAZ));
402 }
403 }
404 }
405
406 void
408 {
409 testcase("Stale validation");
410 // Verify validation becomes stale based solely on time passing, but
411 // use different functions to trigger the check for staleness
412
414 Ledger ledgerA = h["a"];
415 Ledger ledgerAB = h["ab"];
416
417 using Trigger = std::function<void(TestValidations&)>;
418
419 std::vector<Trigger> triggers = {
420 [&](TestValidations& vals) { vals.currentTrusted(); },
421 [&](TestValidations& vals) { vals.getCurrentNodeIDs(); },
422 [&](TestValidations& vals) { vals.getPreferred(genesisLedger); },
423 [&](TestValidations& vals) {
424 vals.getNodesAfter(ledgerA, ledgerA.id());
425 }};
426 for (Trigger trigger : triggers)
427 {
428 TestHarness harness(h.oracle);
429 Node n = harness.makeNode();
430
431 BEAST_EXPECT(
432 ValStatus::current == harness.add(n.validate(ledgerAB)));
433 trigger(harness.vals());
434 BEAST_EXPECT(
435 harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 1);
436 BEAST_EXPECT(
437 harness.vals().getPreferred(genesisLedger) ==
438 std::make_pair(ledgerAB.seq(), ledgerAB.id()));
439 harness.clock().advance(harness.parms().validationCURRENT_LOCAL);
440
441 // trigger check for stale
442 trigger(harness.vals());
443
444 BEAST_EXPECT(
445 harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 0);
446 BEAST_EXPECT(
448 }
449 }
450
451 void
453 {
454 // Test getting number of nodes working on a validation descending
455 // a prescribed one. This count should only be for trusted nodes, but
456 // includes partial and full validations
457
458 using namespace std::chrono_literals;
459 testcase("Get nodes after");
460
462 Ledger ledgerA = h["a"];
463 Ledger ledgerAB = h["ab"];
464 Ledger ledgerABC = h["abc"];
465 Ledger ledgerAD = h["ad"];
466
467 TestHarness harness(h.oracle);
468 Node a = harness.makeNode(), b = harness.makeNode(),
469 c = harness.makeNode(), d = harness.makeNode();
470 c.untrust();
471
472 // first round a,b,c agree, d has is partial
473 BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerA)));
474 BEAST_EXPECT(ValStatus::current == harness.add(b.validate(ledgerA)));
475 BEAST_EXPECT(ValStatus::current == harness.add(c.validate(ledgerA)));
476 BEAST_EXPECT(ValStatus::current == harness.add(d.partial(ledgerA)));
477
478 for (Ledger const& ledger : {ledgerA, ledgerAB, ledgerABC, ledgerAD})
479 BEAST_EXPECT(
480 harness.vals().getNodesAfter(ledger, ledger.id()) == 0);
481
482 harness.clock().advance(5s);
483
484 BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerAB)));
485 BEAST_EXPECT(ValStatus::current == harness.add(b.validate(ledgerABC)));
486 BEAST_EXPECT(ValStatus::current == harness.add(c.validate(ledgerAB)));
487 BEAST_EXPECT(ValStatus::current == harness.add(d.partial(ledgerABC)));
488
489 BEAST_EXPECT(harness.vals().getNodesAfter(ledgerA, ledgerA.id()) == 3);
490 BEAST_EXPECT(
491 harness.vals().getNodesAfter(ledgerAB, ledgerAB.id()) == 2);
492 BEAST_EXPECT(
493 harness.vals().getNodesAfter(ledgerABC, ledgerABC.id()) == 0);
494 BEAST_EXPECT(
495 harness.vals().getNodesAfter(ledgerAD, ledgerAD.id()) == 0);
496
497 // If given a ledger inconsistent with the id, is still able to check
498 // using slower method
499 BEAST_EXPECT(harness.vals().getNodesAfter(ledgerAD, ledgerA.id()) == 1);
500 BEAST_EXPECT(
501 harness.vals().getNodesAfter(ledgerAD, ledgerAB.id()) == 2);
502 }
503
504 void
506 {
507 using namespace std::chrono_literals;
508 testcase("Current trusted validations");
509
511 Ledger ledgerA = h["a"];
512 Ledger ledgerB = h["b"];
513 Ledger ledgerAC = h["ac"];
514
515 TestHarness harness(h.oracle);
516 Node a = harness.makeNode(), b = harness.makeNode();
517 b.untrust();
518
519 BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerA)));
520 BEAST_EXPECT(ValStatus::current == harness.add(b.validate(ledgerB)));
521
522 // Only a is trusted
523 BEAST_EXPECT(harness.vals().currentTrusted().size() == 1);
524 BEAST_EXPECT(
525 harness.vals().currentTrusted()[0].ledgerID() == ledgerA.id());
526 BEAST_EXPECT(harness.vals().currentTrusted()[0].seq() == ledgerA.seq());
527
528 harness.clock().advance(3s);
529
530 for (auto const& node : {a, b})
531 BEAST_EXPECT(
532 ValStatus::current == harness.add(node.validate(ledgerAC)));
533
534 // New validation for a
535 BEAST_EXPECT(harness.vals().currentTrusted().size() == 1);
536 BEAST_EXPECT(
537 harness.vals().currentTrusted()[0].ledgerID() == ledgerAC.id());
538 BEAST_EXPECT(
539 harness.vals().currentTrusted()[0].seq() == ledgerAC.seq());
540
541 // Pass enough time for it to go stale
542 harness.clock().advance(harness.parms().validationCURRENT_LOCAL);
543 BEAST_EXPECT(harness.vals().currentTrusted().empty());
544 }
545
546 void
548 {
549 using namespace std::chrono_literals;
550 testcase("Current public keys");
551
553 Ledger ledgerA = h["a"];
554 Ledger ledgerAC = h["ac"];
555
556 TestHarness harness(h.oracle);
557 Node a = harness.makeNode(), b = harness.makeNode();
558 b.untrust();
559
560 for (auto const& node : {a, b})
561 BEAST_EXPECT(
562 ValStatus::current == harness.add(node.validate(ledgerA)));
563
564 {
565 hash_set<PeerID> const expectedKeys = {a.nodeID(), b.nodeID()};
566 BEAST_EXPECT(harness.vals().getCurrentNodeIDs() == expectedKeys);
567 }
568
569 harness.clock().advance(3s);
570
571 // Change keys and issue partials
572 a.advanceKey();
573 b.advanceKey();
574
575 for (auto const& node : {a, b})
576 BEAST_EXPECT(
577 ValStatus::current == harness.add(node.partial(ledgerAC)));
578
579 {
580 hash_set<PeerID> const expectedKeys = {a.nodeID(), b.nodeID()};
581 BEAST_EXPECT(harness.vals().getCurrentNodeIDs() == expectedKeys);
582 }
583
584 // Pass enough time for them to go stale
585 harness.clock().advance(harness.parms().validationCURRENT_LOCAL);
586 BEAST_EXPECT(harness.vals().getCurrentNodeIDs().empty());
587 }
588
589 void
591 {
592 // Test the Validations functions that calculate a value by ledger ID
593 using namespace std::chrono_literals;
594 testcase("By ledger functions");
595
596 // Several Validations functions return a set of values associated
597 // with trusted ledgers sharing the same ledger ID. The tests below
598 // exercise this logic by saving the set of trusted Validations, and
599 // verifying that the Validations member functions all calculate the
600 // proper transformation of the available ledgers.
601
603 TestHarness harness(h.oracle);
604
605 Node a = harness.makeNode(), b = harness.makeNode(),
606 c = harness.makeNode(), d = harness.makeNode(),
607 e = harness.makeNode();
608
609 c.untrust();
610 // Mix of load fees
611 a.setLoadFee(12);
612 b.setLoadFee(1);
613 c.setLoadFee(12);
614 e.setLoadFee(12);
615
617 trustedValidations;
618
619 //----------------------------------------------------------------------
620 // checkers
621 auto sorted = [](auto vec) {
622 std::sort(vec.begin(), vec.end());
623 return vec;
624 };
625 auto compare = [&]() {
626 for (auto& it : trustedValidations)
627 {
628 auto const& id = it.first.first;
629 auto const& seq = it.first.second;
630 auto const& expectedValidations = it.second;
631
632 BEAST_EXPECT(
633 harness.vals().numTrustedForLedger(id) ==
634 expectedValidations.size());
635 BEAST_EXPECT(
636 sorted(harness.vals().getTrustedForLedger(id, seq)) ==
637 sorted(expectedValidations));
638
639 std::uint32_t baseFee = 0;
640 std::vector<uint32_t> expectedFees;
641 for (auto const& val : expectedValidations)
642 {
643 expectedFees.push_back(val.loadFee().value_or(baseFee));
644 }
645
646 BEAST_EXPECT(
647 sorted(harness.vals().fees(id, baseFee)) ==
648 sorted(expectedFees));
649 }
650 };
651
652 //----------------------------------------------------------------------
653 Ledger ledgerA = h["a"];
654 Ledger ledgerB = h["b"];
655 Ledger ledgerAC = h["ac"];
656
657 // Add a dummy ID to cover unknown ledger identifiers
658 trustedValidations[{Ledger::ID{100}, Ledger::Seq{100}}] = {};
659
660 // first round a,b,c agree
661 for (auto const& node : {a, b, c})
662 {
663 auto const val = node.validate(ledgerA);
664 BEAST_EXPECT(ValStatus::current == harness.add(val));
665 if (val.trusted())
666 trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(
667 val);
668 }
669 // d disagrees
670 {
671 auto const val = d.validate(ledgerB);
672 BEAST_EXPECT(ValStatus::current == harness.add(val));
673 trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(val);
674 }
675 // e only issues partials
676 {
677 BEAST_EXPECT(ValStatus::current == harness.add(e.partial(ledgerA)));
678 }
679
680 harness.clock().advance(5s);
681 // second round, a,b,c move to ledger 2
682 for (auto const& node : {a, b, c})
683 {
684 auto const val = node.validate(ledgerAC);
685 BEAST_EXPECT(ValStatus::current == harness.add(val));
686 if (val.trusted())
687 trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(
688 val);
689 }
690 // d now thinks ledger 1, but cannot re-issue a previously used seq
691 // and attempting it should generate a conflict.
692 {
693 BEAST_EXPECT(
694 ValStatus::conflicting == harness.add(d.partial(ledgerA)));
695 }
696 // e only issues partials
697 {
698 BEAST_EXPECT(
699 ValStatus::current == harness.add(e.partial(ledgerAC)));
700 }
701
702 compare();
703 }
704
705 void
707 {
708 // Verify expiring clears out validations stored by ledger
709 testcase("Expire validations");
710 SuiteJournal j("Validations_test", *this);
712 TestHarness harness(h.oracle);
713 Node const a = harness.makeNode();
714 constexpr Ledger::Seq one(1);
715 constexpr Ledger::Seq two(2);
716
717 // simple cases
718 Ledger const ledgerA = h["a"];
719 BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerA)));
720 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerA.id()) == 1);
721 harness.vals().expire(j);
722 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerA.id()) == 1);
723 harness.clock().advance(harness.parms().validationSET_EXPIRES);
724 harness.vals().expire(j);
725 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerA.id()) == 0);
726
727 // use setSeqToKeep to keep the validation from expire
728 Ledger const ledgerB = h["ab"];
729 BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerB)));
730 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerB.id()) == 1);
731 harness.vals().setSeqToKeep(ledgerB.seq(), ledgerB.seq() + one);
732 harness.clock().advance(harness.parms().validationSET_EXPIRES);
733 harness.vals().expire(j);
734 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerB.id()) == 1);
735 // change toKeep
736 harness.vals().setSeqToKeep(ledgerB.seq() + one, ledgerB.seq() + two);
737 // advance clock slowly
738 int const loops = harness.parms().validationSET_EXPIRES /
739 harness.parms().validationFRESHNESS +
740 1;
741 for (int i = 0; i < loops; ++i)
742 {
743 harness.clock().advance(harness.parms().validationFRESHNESS);
744 harness.vals().expire(j);
745 }
746 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerB.id()) == 0);
747
748 // Allow the validation with high seq to expire
749 Ledger const ledgerC = h["abc"];
750 BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerC)));
751 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerC.id()) == 1);
752 harness.vals().setSeqToKeep(ledgerC.seq() - one, ledgerC.seq());
753 harness.clock().advance(harness.parms().validationSET_EXPIRES);
754 harness.vals().expire(j);
755 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerC.id()) == 0);
756 }
757
758 void
760 {
761 // Test final flush of validations
762 using namespace std::chrono_literals;
763 testcase("Flush validations");
764
766 TestHarness harness(h.oracle);
767 Node a = harness.makeNode(), b = harness.makeNode(),
768 c = harness.makeNode();
769 c.untrust();
770
771 Ledger ledgerA = h["a"];
772 Ledger ledgerAB = h["ab"];
773
775 for (auto const& node : {a, b, c})
776 {
777 auto const val = node.validate(ledgerA);
778 BEAST_EXPECT(ValStatus::current == harness.add(val));
779 expected.emplace(node.nodeID(), val);
780 }
781
782 // Send in a new validation for a, saving the new one into the expected
783 // map after setting the proper prior ledger ID it replaced
784 harness.clock().advance(1s);
785 auto newVal = a.validate(ledgerAB);
786 BEAST_EXPECT(ValStatus::current == harness.add(newVal));
787 expected.find(a.nodeID())->second = newVal;
788 }
789
790 void
792 {
793 using namespace std::chrono_literals;
794 testcase("Preferred Ledger");
795
797 TestHarness harness(h.oracle);
798 Node a = harness.makeNode(), b = harness.makeNode(),
799 c = harness.makeNode(), d = harness.makeNode();
800 c.untrust();
801
802 Ledger ledgerA = h["a"];
803 Ledger ledgerB = h["b"];
804 Ledger ledgerAC = h["ac"];
805 Ledger ledgerACD = h["acd"];
806
807 using Seq = Ledger::Seq;
808
809 auto pref = [](Ledger ledger) {
810 return std::make_pair(ledger.seq(), ledger.id());
811 };
812
813 // Empty (no ledgers)
814 BEAST_EXPECT(harness.vals().getPreferred(ledgerA) == std::nullopt);
815
816 // Single ledger
817 BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerB)));
818 BEAST_EXPECT(harness.vals().getPreferred(ledgerA) == pref(ledgerB));
819 BEAST_EXPECT(harness.vals().getPreferred(ledgerB) == pref(ledgerB));
820
821 // Minimum valid sequence
822 BEAST_EXPECT(
823 harness.vals().getPreferred(ledgerA, Seq{10}) == ledgerA.id());
824
825 // Untrusted doesn't impact preferred ledger
826 // (ledgerB has tie-break over ledgerA)
827 BEAST_EXPECT(ValStatus::current == harness.add(b.validate(ledgerA)));
828 BEAST_EXPECT(ValStatus::current == harness.add(c.validate(ledgerA)));
829 BEAST_EXPECT(ledgerB.id() > ledgerA.id());
830 BEAST_EXPECT(harness.vals().getPreferred(ledgerA) == pref(ledgerB));
831 BEAST_EXPECT(harness.vals().getPreferred(ledgerB) == pref(ledgerB));
832
833 // Partial does break ties
834 BEAST_EXPECT(ValStatus::current == harness.add(d.partial(ledgerA)));
835 BEAST_EXPECT(harness.vals().getPreferred(ledgerA) == pref(ledgerA));
836 BEAST_EXPECT(harness.vals().getPreferred(ledgerB) == pref(ledgerA));
837
838 harness.clock().advance(5s);
839
840 // Parent of preferred-> stick with ledger
841 for (auto const& node : {a, b, c, d})
842 BEAST_EXPECT(
843 ValStatus::current == harness.add(node.validate(ledgerAC)));
844 // Parent of preferred stays put
845 BEAST_EXPECT(harness.vals().getPreferred(ledgerA) == pref(ledgerA));
846 // Earlier different chain, switch
847 BEAST_EXPECT(harness.vals().getPreferred(ledgerB) == pref(ledgerAC));
848 // Later on chain, stays where it is
849 BEAST_EXPECT(harness.vals().getPreferred(ledgerACD) == pref(ledgerACD));
850
851 // Any later grandchild or different chain is preferred
852 harness.clock().advance(5s);
853 for (auto const& node : {a, b, c, d})
854 BEAST_EXPECT(
855 ValStatus::current == harness.add(node.validate(ledgerACD)));
856 for (auto const& ledger : {ledgerA, ledgerB, ledgerACD})
857 BEAST_EXPECT(
858 harness.vals().getPreferred(ledger) == pref(ledgerACD));
859 }
860
861 void
863 {
864 using namespace std::chrono_literals;
865 testcase("Get preferred LCL");
866
868 TestHarness harness(h.oracle);
869 Node a = harness.makeNode();
870
871 Ledger ledgerA = h["a"];
872 Ledger ledgerB = h["b"];
873 Ledger ledgerC = h["c"];
874
875 using ID = Ledger::ID;
876 using Seq = Ledger::Seq;
877
879
880 // No trusted validations or counts sticks with current ledger
881 BEAST_EXPECT(
882 harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) ==
883 ledgerA.id());
884
885 ++peerCounts[ledgerB.id()];
886
887 // No trusted validations, rely on peer counts
888 BEAST_EXPECT(
889 harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) ==
890 ledgerB.id());
891
892 ++peerCounts[ledgerC.id()];
893 // No trusted validations, tied peers goes with larger ID
894 BEAST_EXPECT(ledgerC.id() > ledgerB.id());
895
896 BEAST_EXPECT(
897 harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) ==
898 ledgerC.id());
899
900 peerCounts[ledgerC.id()] += 1000;
901
902 // Single trusted always wins over peer counts
903 BEAST_EXPECT(ValStatus::current == harness.add(a.validate(ledgerA)));
904 BEAST_EXPECT(
905 harness.vals().getPreferredLCL(ledgerA, Seq{0}, peerCounts) ==
906 ledgerA.id());
907 BEAST_EXPECT(
908 harness.vals().getPreferredLCL(ledgerB, Seq{0}, peerCounts) ==
909 ledgerA.id());
910 BEAST_EXPECT(
911 harness.vals().getPreferredLCL(ledgerC, Seq{0}, peerCounts) ==
912 ledgerA.id());
913
914 // Stick with current ledger if trusted validation ledger has too old
915 // of a sequence
916 BEAST_EXPECT(
917 harness.vals().getPreferredLCL(ledgerB, Seq{2}, peerCounts) ==
918 ledgerB.id());
919 }
920
921 void
923 {
924 using namespace std::chrono_literals;
925 testcase("Acquire validated ledger");
926
928 TestHarness harness(h.oracle);
929 Node a = harness.makeNode();
930 Node b = harness.makeNode();
931
932 using ID = Ledger::ID;
933 using Seq = Ledger::Seq;
934
935 // Validate the ledger before it is actually available
936 Validation val = a.validate(ID{2}, Seq{2}, 0s, 0s, true);
937
938 BEAST_EXPECT(ValStatus::current == harness.add(val));
939 // Validation is available
940 BEAST_EXPECT(harness.vals().numTrustedForLedger(ID{2}) == 1);
941 // but ledger based data is not
942 BEAST_EXPECT(harness.vals().getNodesAfter(genesisLedger, ID{0}) == 0);
943 // Initial preferred branch falls back to the ledger we are trying to
944 // acquire
945 BEAST_EXPECT(
946 harness.vals().getPreferred(genesisLedger) ==
947 std::make_pair(Seq{2}, ID{2}));
948
949 // After adding another unavailable validation, the preferred ledger
950 // breaks ties via higher ID
951 BEAST_EXPECT(
953 harness.add(b.validate(ID{3}, Seq{2}, 0s, 0s, true)));
954 BEAST_EXPECT(
955 harness.vals().getPreferred(genesisLedger) ==
956 std::make_pair(Seq{2}, ID{3}));
957
958 // Create the ledger
959 Ledger ledgerAB = h["ab"];
960 // Now it should be available
961 BEAST_EXPECT(harness.vals().getNodesAfter(genesisLedger, ID{0}) == 1);
962
963 // Create a validation that is not available
964 harness.clock().advance(5s);
965 Validation val2 = a.validate(ID{4}, Seq{4}, 0s, 0s, true);
966 BEAST_EXPECT(ValStatus::current == harness.add(val2));
967 BEAST_EXPECT(harness.vals().numTrustedForLedger(ID{4}) == 1);
968 BEAST_EXPECT(
969 harness.vals().getPreferred(genesisLedger) ==
970 std::make_pair(ledgerAB.seq(), ledgerAB.id()));
971
972 // Another node requesting that ledger still doesn't change things
973 Validation val3 = b.validate(ID{4}, Seq{4}, 0s, 0s, true);
974 BEAST_EXPECT(ValStatus::current == harness.add(val3));
975 BEAST_EXPECT(harness.vals().numTrustedForLedger(ID{4}) == 2);
976 BEAST_EXPECT(
977 harness.vals().getPreferred(genesisLedger) ==
978 std::make_pair(ledgerAB.seq(), ledgerAB.id()));
979
980 // Switch to validation that is available
981 harness.clock().advance(5s);
982 Ledger ledgerABCDE = h["abcde"];
983 BEAST_EXPECT(ValStatus::current == harness.add(a.partial(ledgerABCDE)));
984 BEAST_EXPECT(ValStatus::current == harness.add(b.partial(ledgerABCDE)));
985 BEAST_EXPECT(
986 harness.vals().getPreferred(genesisLedger) ==
987 std::make_pair(ledgerABCDE.seq(), ledgerABCDE.id()));
988 }
989
990 void
992 {
993 testcase("NumTrustedForLedger");
995 TestHarness harness(h.oracle);
996 Node a = harness.makeNode();
997 Node b = harness.makeNode();
998 Ledger ledgerA = h["a"];
999
1000 BEAST_EXPECT(ValStatus::current == harness.add(a.partial(ledgerA)));
1001 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerA.id()) == 0);
1002
1003 BEAST_EXPECT(ValStatus::current == harness.add(b.validate(ledgerA)));
1004 BEAST_EXPECT(harness.vals().numTrustedForLedger(ledgerA.id()) == 1);
1005 }
1006
1007 void
1009 {
1010 testcase("SeqEnforcer");
1011 using Seq = Ledger::Seq;
1012 using namespace std::chrono;
1013
1015 SeqEnforcer<Seq> enforcer;
1016
1018
1019 BEAST_EXPECT(enforcer(clock.now(), Seq{1}, p));
1020 BEAST_EXPECT(enforcer(clock.now(), Seq{10}, p));
1021 BEAST_EXPECT(!enforcer(clock.now(), Seq{5}, p));
1022 BEAST_EXPECT(!enforcer(clock.now(), Seq{9}, p));
1023 clock.advance(p.validationSET_EXPIRES - 1ms);
1024 BEAST_EXPECT(!enforcer(clock.now(), Seq{1}, p));
1025 clock.advance(2ms);
1026 BEAST_EXPECT(enforcer(clock.now(), Seq{1}, p));
1027 }
1028
1029 void
1031 {
1032 testcase("TrustChanged");
1033 using namespace std::chrono;
1034
1035 auto checker = [this](
1036 TestValidations& vals,
1037 hash_set<PeerID> const& listed,
1038 std::vector<Validation> const& trustedVals) {
1039 Ledger::ID testID = trustedVals.empty() ? this->genesisLedger.id()
1040 : trustedVals[0].ledgerID();
1041 Ledger::Seq testSeq = trustedVals.empty()
1042 ? this->genesisLedger.seq()
1043 : trustedVals[0].seq();
1044 BEAST_EXPECT(vals.currentTrusted() == trustedVals);
1045 BEAST_EXPECT(vals.getCurrentNodeIDs() == listed);
1046 BEAST_EXPECT(
1047 vals.getNodesAfter(this->genesisLedger, genesisLedger.id()) ==
1048 trustedVals.size());
1049 if (trustedVals.empty())
1050 BEAST_EXPECT(
1051 vals.getPreferred(this->genesisLedger) == std::nullopt);
1052 else
1053 BEAST_EXPECT(
1054 vals.getPreferred(this->genesisLedger)->second == testID);
1055 BEAST_EXPECT(
1056 vals.getTrustedForLedger(testID, testSeq) == trustedVals);
1057 BEAST_EXPECT(
1058 vals.numTrustedForLedger(testID) == trustedVals.size());
1059 };
1060
1061 {
1062 // Trusted to untrusted
1064 TestHarness harness(h.oracle);
1065 Node a = harness.makeNode();
1066 Ledger ledgerAB = h["ab"];
1067 Validation v = a.validate(ledgerAB);
1068 BEAST_EXPECT(ValStatus::current == harness.add(v));
1069
1070 hash_set<PeerID> listed({a.nodeID()});
1071 std::vector<Validation> trustedVals({v});
1072 checker(harness.vals(), listed, trustedVals);
1073
1074 trustedVals.clear();
1075 harness.vals().trustChanged({}, {a.nodeID()});
1076 checker(harness.vals(), listed, trustedVals);
1077 }
1078
1079 {
1080 // Untrusted to trusted
1082 TestHarness harness(h.oracle);
1083 Node a = harness.makeNode();
1084 a.untrust();
1085 Ledger ledgerAB = h["ab"];
1086 Validation v = a.validate(ledgerAB);
1087 BEAST_EXPECT(ValStatus::current == harness.add(v));
1088
1089 hash_set<PeerID> listed({a.nodeID()});
1090 std::vector<Validation> trustedVals;
1091 checker(harness.vals(), listed, trustedVals);
1092
1093 trustedVals.push_back(v);
1094 harness.vals().trustChanged({a.nodeID()}, {});
1095 checker(harness.vals(), listed, trustedVals);
1096 }
1097
1098 {
1099 // Trusted but not acquired -> untrusted
1101 TestHarness harness(h.oracle);
1102 Node a = harness.makeNode();
1103 Validation v =
1104 a.validate(Ledger::ID{2}, Ledger::Seq{2}, 0s, 0s, true);
1105 BEAST_EXPECT(ValStatus::current == harness.add(v));
1106
1107 hash_set<PeerID> listed({a.nodeID()});
1108 std::vector<Validation> trustedVals({v});
1109 auto& vals = harness.vals();
1110 BEAST_EXPECT(vals.currentTrusted() == trustedVals);
1111 BEAST_EXPECT(
1112 vals.getPreferred(genesisLedger)->second == v.ledgerID());
1113 BEAST_EXPECT(
1114 vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0);
1115
1116 trustedVals.clear();
1117 harness.vals().trustChanged({}, {a.nodeID()});
1118 // make acquiring ledger available
1119 h["ab"];
1120 BEAST_EXPECT(vals.currentTrusted() == trustedVals);
1121 BEAST_EXPECT(vals.getPreferred(genesisLedger) == std::nullopt);
1122 BEAST_EXPECT(
1123 vals.getNodesAfter(genesisLedger, genesisLedger.id()) == 0);
1124 }
1125 }
1126
1127 void
1145};
1146
1147BEAST_DEFINE_TESTSUITE(Validations, consensus, ripple);
1148} // namespace csf
1149} // namespace test
1150} // namespace ripple
Abstract interface to a clock.
Manual clock implementation.
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
std::chrono::time_point< NetClock > time_point
Definition chrono.h:69
Enforce validation increasing sequence requirement.
Maintains current and recent ledger validations.
std::optional< std::pair< Seq, ID > > getPreferred(Ledger const &curr)
Return the sequence number and ID of the preferred working ledger.
std::size_t numTrustedForLedger(ID const &ledgerID)
Count the number of trusted full validations for the given ledger.
auto getCurrentNodeIDs() -> hash_set< NodeID >
Get the set of node ids associated with current validations.
std::size_t getNodesAfter(Ledger const &ledger, ID const &ledgerID)
Count the number of current trusted validators working on a ledger after the specified one.
std::vector< WrappedValidationType > getTrustedForLedger(ID const &ledgerID, Seq const &seq)
Get trusted full validations for a specific ledger.
ID getPreferredLCL(Ledger const &lcl, Seq minSeq, hash_map< ID, std::uint32_t > const &peerCounts)
Determine the preferred last closed ledger for the next consensus round.
void trustChanged(hash_set< NodeID > const &added, hash_set< NodeID > const &removed)
Update trust status of validations.
std::vector< WrappedValidationType > currentTrusted()
Get the currently trusted full validations.
void setSeqToKeep(Seq const &low, Seq const &high)
Set the range [low, high) of validations to keep from expire.
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
void expire(beast::Journal &j)
Expire old validation sets.
std::vector< std::uint32_t > fees(ID const &ledgerID, std::uint32_t baseFee)
Returns fees reported by trusted full validators in the given ledger.
Oracle maintaining unique ledgers for a simulation.
Definition ledgers.h:250
std::optional< Ledger > lookup(Ledger::ID const &id) const
Find the ledger with the given ID.
Definition ledgers.cpp:129
A ledger is a set of observed transactions and a sequence number identifying the ledger.
Definition ledgers.h:64
tagged_integer< std::uint32_t, SeqTag > Seq
Definition ledgers.h:69
tagged_integer< std::uint32_t, IdTag > ID
Definition ledgers.h:72
Validation of a specific ledger by a specific Peer.
Definition Validation.h:50
Ledger::ID ledgerID() const
Definition Validation.h:90
PeerID const & nodeID() const
Definition Validation.h:120
std::optional< Ledger > acquire(Ledger::ID const &id)
Validation partial(Ledger ledger) const
std::optional< std::uint32_t > loadFee_
Validation validate(Ledger ledger) const
Node(PeerID nodeID, clock_type const &c)
Validation validate(Ledger ledger, NetClock::duration signOffset, NetClock::duration seenOffset) const
Validation validate(Ledger::ID id, Ledger::Seq seq, NetClock::duration signOffset, NetClock::duration seenOffset, bool full) const
beast::manual_clock< std::chrono::steady_clock > clock_
beast::abstract_clock< std::chrono::steady_clock > const clock_type
void run() override
Runs the suite.
static NetClock::time_point toNetClock(clock_type const &c)
Set the fee on a JTx.
Definition fee.h:37
T emplace(T... args)
T find(T... args)
T is_same_v
T make_pair(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
constexpr Number one
Definition Number.cpp:175
ValStatus
Status of validation we received.
@ badSeq
A validation violates the increasing seq requirement.
@ stale
Not current or was older than current from this node.
@ current
This was a new validation and was added.
@ conflicting
Multiple validations by a validator for different ledgers.
T push_back(T... args)
T sort(T... args)
Timing parameters to control validation staleness and expiration.
Definition Validations.h:47
std::chrono::seconds validationCURRENT_LOCAL
Duration a validation remains current after first observed.
Definition Validations.h:64
std::chrono::seconds validationFRESHNESS
How long we consider a validation fresh.
Definition Validations.h:89
std::chrono::seconds validationSET_EXPIRES
Duration a set of validations for a given ledger hash remain valid.
Definition Validations.h:79
std::chrono::seconds validationCURRENT_WALL
The number of seconds a validation remains current after its ledger's close time.
Definition Validations.h:56
std::chrono::seconds validationCURRENT_EARLY
Duration pre-close in which validations are acceptable.
Definition Validations.h:71
Helper for writing unit tests with controlled ledger histories.
Definition ledgers.h:329
Set the sequence number on a JTx.
Definition seq.h:34