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