xrpld
Loading...
Searching...
No Matches
Validations.h
1#pragma once
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/UnorderedContainers.h>
5#include <xrpl/basics/chrono.h>
6#include <xrpl/beast/clock/abstract_clock.h>
7#include <xrpl/beast/container/aged_container_utility.h>
8#include <xrpl/beast/container/aged_unordered_map.h>
9#include <xrpl/beast/hash/uhash.h>
10#include <xrpl/beast/utility/Journal.h>
11#include <xrpl/beast/utility/instrumentation.h>
12#include <xrpl/consensus/LedgerTrie.h>
13#include <xrpl/json/json_value.h>
14
15#include <algorithm>
16#include <chrono>
17#include <cstddef>
18#include <cstdint>
19#include <mutex>
20#include <optional>
21#include <string>
22#include <type_traits>
23#include <utility>
24#include <vector>
25
26namespace xrpl {
27
85
93template <class Seq>
95{
96 using time_point = std::chrono::steady_clock::time_point;
97 Seq seq_{0};
99
100public:
114 bool
116 {
117 if (now > (when_ + p.validationSetExpires))
118 seq_ = Seq{0};
119 if (s <= seq_)
120 return false;
121 seq_ = s;
122 when_ = now;
123 return true;
124 }
125
126 [[nodiscard]] Seq
127 largest() const
128 {
129 return seq_;
130 }
131};
132
145inline bool
147 ValidationParms const& p,
149 NetClock::time_point signTime,
150 NetClock::time_point seenTime)
151{
152 // Because this can be called on untrusted, possibly
153 // malicious validations, we do our math in a way
154 // that avoids any chance of overflowing or underflowing
155 // the signing time. All of the expressions below are
156 // promoted from unsigned 32 bit to signed 64 bit prior
157 // to computation.
158
159 return (signTime > (now - p.validationCurrentEarly)) &&
160 (signTime < (now + p.validationCurrentWall)) &&
161 ((seenTime == NetClock::time_point{}) || (seenTime < (now + p.validationCurrentLocal)));
162}
163
189
190inline std::string
192{
193 switch (m)
194 {
196 return "current";
197 case ValStatus::Stale:
198 return "stale";
200 return "badSeq";
202 return "multiple";
204 return "conflicting";
205 default:
206 return "unknown";
207 }
208}
209
297template <class Adaptor>
299{
300 using Mutex = Adaptor::Mutex;
301 using Validation = Adaptor::Validation;
302 using Ledger = Adaptor::Ledger;
303 using ID = Ledger::ID;
304 using Seq = Ledger::Seq;
305 using NodeID = Validation::NodeID;
306 using NodeKey = Validation::NodeKey;
307
309 std::decay_t<std::invoke_result_t<decltype(&Validation::unwrap), Validation>>;
310
311 // Manages concurrent access to members
312 mutable Mutex mutex_;
313
314 // Validations from currently listed and trusted nodes (partial and full)
316
317 // Used to enforce the largest validation invariant for the local node
319
320 // Sequence of the largest validation received from each node
322
326 beast::
327 AgedUnorderedMap<ID, HashMap<NodeID, Validation>, std::chrono::steady_clock, beast::Uhash<>>
329
330 // Partial and full validations indexed by sequence
332 Seq,
337
338 // A range [low_, high_) of validations to keep from expire
340 {
343 };
345
346 // Represents the ancestry of validated ledgers
348
349 // Last (validated) ledger successfully acquired. If in this map, it is
350 // accounted for in the trie.
352
353 // Set of ledgers being acquired from the network
355
356 // Parameters to determine validation staleness
358
359 // Adaptor instance
360 // Is NOT managed by the mutex_ above
361 Adaptor adaptor_;
362
363private:
364 // Remove support of a validated ledger
365 void
366 removeTrie(std::scoped_lock<Mutex> const&, NodeID const& nodeID, Validation const& val)
367 {
368 {
369 auto it = acquiring_.find(std::make_pair(val.seq(), val.ledgerID()));
370 if (it != acquiring_.end())
371 {
372 it->second.erase(nodeID);
373 if (it->second.empty())
374 acquiring_.erase(it);
375 }
376 }
377 {
378 auto it = lastLedger_.find(nodeID);
379 if (it != lastLedger_.end() && it->second.id() == val.ledgerID())
380 {
381 trie_.remove(it->second);
382 lastLedger_.erase(nodeID);
383 }
384 }
385 }
386
387 // Check if any pending acquire ledger requests are complete
388 void
390 {
391 for (auto it = acquiring_.begin(); it != acquiring_.end();)
392 {
393 if (std::optional<Ledger> ledger = adaptor_.acquire(it->first.second))
394 {
395 for (NodeID const& nodeID : it->second)
396 updateTrie(lock, nodeID, *ledger);
397
398 it = acquiring_.erase(it);
399 }
400 else
401 {
402 ++it;
403 }
404 }
405 }
406
407 // Update the trie to reflect a new validated ledger
408 void
409 updateTrie(std::scoped_lock<Mutex> const&, NodeID const& nodeID, Ledger ledger)
410 {
411 auto const [it, inserted] = lastLedger_.emplace(nodeID, ledger);
412 if (!inserted)
413 {
414 trie_.remove(it->second);
415 it->second = ledger;
416 }
417 trie_.insert(ledger);
418 }
419
434 void
436 std::scoped_lock<Mutex> const& lock,
437 NodeID const& nodeID,
438 Validation const& val,
440 {
441 XRPL_ASSERT(val.trusted(), "xrpl::Validations::updateTrie : trusted input validation");
442
443 // Clear any prior acquiring ledger for this node
444 if (prior)
445 {
446 auto it = acquiring_.find(*prior);
447 if (it != acquiring_.end())
448 {
449 it->second.erase(nodeID);
450 if (it->second.empty())
451 acquiring_.erase(it);
452 }
453 }
454
455 checkAcquired(lock);
456
457 std::pair<Seq, ID> const valPair{val.seq(), val.ledgerID()};
458 auto it = acquiring_.find(valPair);
459 if (it != acquiring_.end())
460 {
461 it->second.insert(nodeID);
462 }
463 else
464 {
465 if (std::optional<Ledger> ledger = adaptor_.acquire(val.ledgerID()))
466 {
467 updateTrie(lock, nodeID, *ledger);
468 }
469 else
470 {
471 acquiring_[valPair].insert(nodeID);
472 }
473 }
474 }
475
488 template <class F>
489 auto
491 {
492 // Call current to flush any stale validations
493 current(lock, [](auto) {}, [](auto, auto) {});
494 checkAcquired(lock);
495 return f(trie_);
496 }
497
514
515 template <class Pre, class F>
516 void
517 current(std::scoped_lock<Mutex> const& lock, Pre&& pre, F&& f)
518 {
519 NetClock::time_point const t = adaptor_.now();
520 pre(current_.size());
521 auto it = current_.begin();
522 while (it != current_.end())
523 {
524 // Check for staleness
525 if (!isCurrent(parms_, t, it->second.signTime(), it->second.seenTime()))
526 {
527 removeTrie(lock, it->first, it->second);
528 it = current_.erase(it);
529 }
530 else
531 {
532 auto cit = typename decltype(current_)::const_iterator{it};
533 // contains a live record
534 f(cit->first, cit->second);
535 ++it;
536 }
537 }
538 }
539
553 template <class Pre, class F>
554 void
555 byLedger(std::scoped_lock<Mutex> const&, ID const& ledgerID, Pre&& pre, F&& f)
556 {
557 auto it = byLedger_.find(ledgerID);
558 if (it != byLedger_.end())
559 {
560 // Update set time since it is being used
561 byLedger_.touch(it);
562 pre(it->second.size());
563 for (auto const& [key, val] : it->second)
564 f(key, val);
565 }
566 }
567
568public:
576 template <class... Ts>
578 ValidationParms const& p,
580 Ts&&... ts)
581 : byLedger_(c), bySequence_(c), parms_(p), adaptor_(std::forward<Ts>(ts)...)
582 {
583 }
584
588 Adaptor const&
589 adaptor() const
590 {
591 return adaptor_;
592 }
593
597 ValidationParms const&
598 parms() const
599 {
600 return parms_;
601 }
602
611 bool
613 {
614 std::scoped_lock const lock{mutex_};
615 return localSeqEnforcer_(byLedger_.clock().now(), s, parms_);
616 }
617
628 add(NodeID const& nodeID, Validation const& val)
629 {
630 if (!isCurrent(parms_, adaptor_.now(), val.signTime(), val.seenTime()))
631 return ValStatus::Stale;
632
633 {
634 std::scoped_lock const lock{mutex_};
635
636 // Check that validation sequence is greater than any non-expired
637 // validations sequence from that validator; if it's not, perform
638 // additional work to detect Byzantine validations
639 auto const now = byLedger_.clock().now();
640
641 auto const [seqit, seqinserted] = bySequence_[val.seq()].emplace(nodeID, val);
642
643 if (!seqinserted)
644 {
645 // Check if the entry we're already tracking was signed
646 // long enough ago that we can disregard it.
647 auto const diff = std::max(seqit->second.signTime(), val.signTime()) -
648 std::min(seqit->second.signTime(), val.signTime());
649
650 if (diff > parms_.validationCurrentWall &&
651 val.signTime() > seqit->second.signTime())
652 seqit->second = val;
653 }
654
655 // Enforce monotonically increasing sequences for validations
656 // by a given node, and run the active Byzantine detector:
657 if (auto& enf = seqEnforcers_[nodeID]; !enf(now, val.seq(), parms_))
658 {
659 // If the validation is for the same sequence as one we are
660 // tracking, check it closely:
661 if (seqit->second.seq() == val.seq())
662 {
663 // Two validations for the same sequence but for different
664 // ledgers. This could be the result of misconfiguration
665 // but it can also mean a Byzantine validator.
666 if (seqit->second.ledgerID() != val.ledgerID())
668
669 // Two validations for the same sequence and for the same
670 // ledger with different sign times. This could be the
671 // result of a misconfiguration but it can also mean a
672 // Byzantine validator.
673 if (seqit->second.signTime() != val.signTime())
675
676 // Two validations for the same sequence but with different
677 // cookies. This is probably accidental misconfiguration.
678 if (seqit->second.cookie() != val.cookie())
679 return ValStatus::Multiple;
680 }
681
682 return ValStatus::BadSeq;
683 }
684
685 byLedger_[val.ledgerID()].insert_or_assign(nodeID, val);
686
687 auto const [it, inserted] = current_.emplace(nodeID, val);
688 if (!inserted)
689 {
690 // Replace existing only if this one is newer
691 Validation const& oldVal = it->second;
692 if (val.signTime() > oldVal.signTime())
693 {
694 std::pair<Seq, ID> old(oldVal.seq(), oldVal.ledgerID());
695 it->second = val;
696 if (val.trusted())
697 updateTrie(lock, nodeID, val, old);
698 }
699 else
700 {
701 return ValStatus::Stale;
702 }
703 }
704 else if (val.trusted())
705 {
706 updateTrie(lock, nodeID, val, std::nullopt);
707 }
708 }
709
710 return ValStatus::Current;
711 }
712
719 void
720 setSeqToKeep(Seq const& low, Seq const& high)
721 {
722 std::scoped_lock const lock{mutex_};
723 XRPL_ASSERT(low < high, "xrpl::Validations::setSeqToKeep : valid inputs");
724 toKeep_ = {low, high};
725 }
726
733 void
735 {
736 auto const start = std::chrono::steady_clock::now();
737 {
738 std::scoped_lock const lock{mutex_};
739 if (toKeep_)
740 {
741 // We only need to refresh the keep range when it's just about
742 // to expire. Track the next time we need to refresh.
743 static std::chrono::steady_clock::time_point kRefreshTime;
744 if (auto const now = byLedger_.clock().now(); kRefreshTime <= now)
745 {
746 // The next refresh time is shortly before the expiration
747 // time from now.
748 kRefreshTime = now + parms_.validationSetExpires - parms_.validationFRESHNESS;
749
750 for (auto i = byLedger_.begin(); i != byLedger_.end(); ++i)
751 {
752 auto const& validationMap = i->second;
753 if (!validationMap.empty())
754 {
755 auto const seq = validationMap.begin()->second.seq();
756 if (toKeep_->low <= seq && seq < toKeep_->high)
757 {
758 byLedger_.touch(i);
759 }
760 }
761 }
762
763 for (auto i = bySequence_.begin(); i != bySequence_.end(); ++i)
764 {
765 if (toKeep_->low <= i->first && i->first < toKeep_->high)
766 {
767 bySequence_.touch(i);
768 }
769 }
770 }
771 }
772
773 beast::expire(byLedger_, parms_.validationSetExpires);
774 beast::expire(bySequence_, parms_.validationSetExpires);
775 }
776 JLOG(j.debug()) << "Validations sets sweep lock duration "
779 .count()
780 << "ms";
781 }
782
793 void
794 trustChanged(HashSet<NodeID> const& added, HashSet<NodeID> const& removed)
795 {
796 std::scoped_lock const lock{mutex_};
797
798 for (auto& [nodeId, validation] : current_)
799 {
800 if (added.find(nodeId) != added.end())
801 {
802 validation.setTrusted();
803 updateTrie(lock, nodeId, validation, std::nullopt);
804 }
805 else if (removed.find(nodeId) != removed.end())
806 {
807 validation.setUntrusted();
808 removeTrie(lock, nodeId, validation);
809 }
810 }
811
812 for (auto& [_, validationMap] : byLedger_)
813 {
814 (void)_;
815 for (auto& [nodeId, validation] : validationMap)
816 {
817 if (added.find(nodeId) != added.end())
818 {
819 validation.setTrusted();
820 }
821 else if (removed.find(nodeId) != removed.end())
822 {
823 validation.setUntrusted();
824 }
825 }
826 }
827 }
828
831 {
832 std::scoped_lock const lock{mutex_};
833 return trie_.getJson();
834 }
835
850 getPreferred(Ledger const& curr)
851 {
852 std::scoped_lock const lock{mutex_};
853 std::optional<SpanTip<Ledger>> preferred = withTrie(lock, [this](LedgerTrie<Ledger>& trie) {
854 return trie.getPreferred(localSeqEnforcer_.largest());
855 });
856 // No trusted validations to determine branch
857 if (!preferred)
858 {
859 // fall back to majority over acquiring ledgers
860 auto it = std::ranges::max_element(acquiring_, [](auto const& a, auto const& b) {
861 std::pair<Seq, ID> const& aKey = a.first;
862 typename HashSet<NodeID>::size_type const& aSize = a.second.size();
863 std::pair<Seq, ID> const& bKey = b.first;
864 typename HashSet<NodeID>::size_type const& bSize = b.second.size();
865 // order by number of trusted peers validating that ledger
866 // break ties with ledger ID
867 return std::tie(aSize, aKey.second) < std::tie(bSize, bKey.second);
868 });
869 if (it != acquiring_.end())
870 return it->first;
871 return std::nullopt;
872 }
873
874 // If we are the parent of the preferred ledger, stick with our
875 // current ledger since we might be about to generate it
876 if (preferred->seq == curr.seq() + Seq{1} && preferred->ancestor(curr.seq()) == curr.id())
877 return std::make_pair(curr.seq(), curr.id());
878
879 // A ledger ahead of us is preferred regardless of whether it is
880 // a descendant of our working ledger or it is on a different chain
881 if (preferred->seq > curr.seq())
882 return std::make_pair(preferred->seq, preferred->id);
883
884 // Only switch to earlier or same sequence number
885 // if it is a different chain.
886 if (curr[preferred->seq] != preferred->id)
887 return std::make_pair(preferred->seq, preferred->id);
888
889 // Stick with current ledger
890 return std::make_pair(curr.seq(), curr.id());
891 }
892
903 ID
904 getPreferred(Ledger const& curr, Seq minValidSeq)
905 {
907 if (preferred && preferred->first >= minValidSeq)
908 return preferred->second;
909 return curr.id();
910 }
911
929 ID
930 getPreferredLCL(Ledger const& lcl, Seq minSeq, HashMap<ID, std::uint32_t> const& peerCounts)
931 {
933
934 // Trusted validations exist, but stick with local preferred ledger if
935 // preferred is in the past
936 if (preferred)
937 return (preferred->first >= minSeq) ? preferred->second : lcl.id();
938
939 // Otherwise, rely on peer ledgers
940 auto it = std::ranges::max_element(peerCounts, [](auto const& a, auto const& b) {
941 // Prefer larger counts, then larger ids on ties
942 // (max_element expects this to return true if a < b)
943 return std::tie(a.second, a.first) < std::tie(b.second, b.first);
944 });
945
946 if (it != peerCounts.end())
947 return it->first;
948 return lcl.id();
949 }
950
964 getNodesAfter(Ledger const& ledger, ID const& ledgerID)
965 {
966 std::scoped_lock const lock{mutex_};
967
968 // Use trie if ledger is the right one
969 if (ledger.id() == ledgerID)
970 {
971 return withTrie(lock, [&ledger](LedgerTrie<Ledger>& trie) {
972 return trie.branchSupport(ledger) - trie.tipSupport(ledger);
973 });
974 }
975
976 // Count parent ledgers as fallback
977 return std::ranges::count_if(lastLedger_, [&ledgerID](auto const& it) {
978 auto const& curr = it.second;
979 return curr.seq() > Seq{0} && curr[curr.seq() - Seq{1}] == ledgerID;
980 });
981 }
982
990 {
992 std::scoped_lock const lock{mutex_};
993 current(
994 lock,
995 [&](std::size_t numValidations) { ret.reserve(numValidations); },
996 [&](NodeID const&, Validation const& v) {
997 if (v.trusted() && v.full())
998 ret.push_back(v.unwrap());
999 });
1000 return ret;
1001 }
1002
1008 auto
1010 {
1011 HashSet<NodeID> ret;
1012 std::scoped_lock const lock{mutex_};
1013 current(
1014 lock,
1015 [&](std::size_t numValidations) { ret.reserve(numValidations); },
1016 [&](NodeID const& nid, Validation const&) { ret.insert(nid); });
1017
1018 return ret;
1019 }
1020
1028 numTrustedForLedger(ID const& ledgerID)
1029 {
1030 std::size_t count = 0;
1031 std::scoped_lock const lock{mutex_};
1032 byLedger(
1033 lock,
1034 ledgerID,
1035 [&](std::size_t) {}, // nothing to reserve
1036 [&](NodeID const&, Validation const& v) {
1037 if (v.trusted() && v.full())
1038 ++count;
1039 });
1040 return count;
1041 }
1042
1051 getTrustedForLedger(ID const& ledgerID, Seq const& seq)
1052 {
1054 std::scoped_lock const lock{mutex_};
1055 byLedger(
1056 lock,
1057 ledgerID,
1058 [&](std::size_t numValidations) { res.reserve(numValidations); },
1059 [&](NodeID const&, Validation const& v) {
1060 if (v.trusted() && v.full() && v.seq() == seq)
1061 res.emplace_back(v.unwrap());
1062 });
1063
1064 return res;
1065 }
1066
1075 fees(ID const& ledgerID, std::uint32_t baseFee)
1076 {
1078 std::scoped_lock const lock{mutex_};
1079 byLedger(
1080 lock,
1081 ledgerID,
1082 [&](std::size_t numValidations) { res.reserve(numValidations); },
1083 [&](NodeID const&, Validation const& v) {
1084 if (v.trusted() && v.full())
1085 {
1086 std::optional<std::uint32_t> loadFee = v.loadFee();
1087 if (loadFee)
1088 {
1089 res.push_back(*loadFee);
1090 }
1091 else
1092 {
1093 res.push_back(baseFee);
1094 }
1095 }
1096 });
1097 return res;
1098 }
1099
1103 void
1105 {
1106 std::scoped_lock const lock{mutex_};
1107 current_.clear();
1108 }
1109
1127 laggards(Seq const seq, HashSet<NodeKey>& trustedKeys)
1128 {
1130
1131 current(
1133 [](std::size_t) {},
1134 [&](NodeID const&, Validation const& v) {
1135 if (adaptor_.now() < v.seenTime() + parms_.validationFRESHNESS &&
1136 trustedKeys.find(v.key()) != trustedKeys.end())
1137 {
1138 trustedKeys.erase(v.key());
1139 if (seq > v.seq())
1140 ++laggards;
1141 }
1142 });
1143
1144 return laggards;
1145 }
1146
1149 {
1150 std::scoped_lock const lock{mutex_};
1151 return current_.size();
1152 }
1153
1156 {
1157 std::scoped_lock const lock{mutex_};
1158 return seqEnforcers_.size();
1159 }
1160
1163 {
1164 std::scoped_lock const lock{mutex_};
1165 return byLedger_.size();
1166 }
1167
1170 {
1171 std::scoped_lock const lock{mutex_};
1172 return bySequence_.size();
1173 }
1174};
1175
1176} // namespace xrpl
Abstract interface to a clock.
A generic endpoint for log messages.
Definition Journal.h:44
Stream debug() const
Definition Journal.h:344
Represents a JSON value.
Definition json_value.h:117
Ancestry trie of ledgers.
Definition LedgerTrie.h:331
std::uint32_t tipSupport(Ledger const &ledger) const
Return count of tip support for the specific ledger.
Definition LedgerTrie.h:582
std::uint32_t branchSupport(Ledger const &ledger) const
Return the count of branch support for the specific ledger.
Definition LedgerTrie.h:597
std::optional< SpanTip< Ledger > > getPreferred(Seq const largestIssued) const
Return the preferred ledger ID.
Definition LedgerTrie.h:672
std::chrono::time_point< NetClock > time_point
Definition chrono.h:48
Seq seq() const
The sequence (index) of the ledger.
ID id() const
The ID (hash) of the ledger.
std::uint32_t seq() const
Validated ledger's sequence number (0 if none).
bool trusted() const
Whether the validation is considered trusted.
UInt256 ledgerID() const
Validated ledger's hash.
NetClock::time_point seenTime() const
Validated ledger's first seen time.
std::uint64_t cookie() const
Get the cookie specified in the validation (0 if not set).
NetClock::time_point signTime() const
Validation's signing time.
Enforce validation increasing sequence requirement.
Definition Validations.h:95
std::chrono::steady_clock::time_point time_point
Definition Validations.h:96
bool operator()(time_point now, Seq s, ValidationParms const &p)
Try advancing the largest observed validation ledger sequence.
Seq largest() const
time_point when_
Definition Validations.h:98
void updateTrie(std::scoped_lock< Mutex > const &, NodeID const &nodeID, Ledger ledger)
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.
void expire(beast::Journal const &j)
Expire old validation sets.
bool canValidateSeq(Seq const s)
Return whether the local node can issue a validation for the given sequence number.
HashMap< NodeID, Ledger > lastLedger_
HashMap< NodeID, SeqEnforcer< Seq > > seqEnforcers_
std::size_t numTrustedForLedger(ID const &ledgerID)
Count the number of trusted full validations for the given ledger.
std::vector< WrappedValidationType > getTrustedForLedger(ID const &ledgerID, Seq const &seq)
Get trusted full validations for a specific ledger.
HashMap< std::pair< Seq, ID >, HashSet< NodeID > > acquiring_
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
ID getPreferredLCL(Ledger const &lcl, Seq minSeq, HashMap< ID, std::uint32_t > const &peerCounts)
Determine the preferred last closed ledger for the next consensus round.
HashMap< NodeID, Validation > current_
ValidationParms const & parms() const
Return the validation timing parameters.
auto getCurrentNodeIDs() -> HashSet< NodeID >
Get the set of node ids associated with current validations.
void checkAcquired(std::scoped_lock< Mutex > const &lock)
Adaptor::Mutex Mutex
Adaptor const & adaptor() const
Return the adaptor instance.
beast::AgedUnorderedMap< Seq, HashMap< NodeID, Validation >, std::chrono::steady_clock, beast::Uhash<> > bySequence_
std::size_t laggards(Seq const seq, HashSet< NodeKey > &trustedKeys)
Return quantity of lagging proposers, and remove online proposers for purposes of evaluating whether ...
void trustChanged(HashSet< NodeID > const &added, HashSet< NodeID > const &removed)
Update trust status of validations.
std::size_t sizeOfCurrentCache() const
void updateTrie(std::scoped_lock< Mutex > const &lock, NodeID const &nodeID, Validation const &val, std::optional< std::pair< Seq, ID > > prior)
Process a new validation.
std::optional< std::pair< Seq, ID > > getPreferred(Ledger const &curr)
Return the sequence number and ID of the preferred working ledger.
void flush()
Flush all current 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.
auto withTrie(std::scoped_lock< Mutex > const &lock, F &&f)
Use the trie for a calculation.
beast::AgedUnorderedMap< ID, HashMap< NodeID, Validation >, std::chrono::steady_clock, beast::Uhash<> > byLedger_
std::size_t sizeOfByLedgerCache() const
Adaptor::Validation Validation
std::size_t sizeOfBySequenceCache() const
json::Value getJsonTrie() const
std::decay_t< std::invoke_result_t< decltype(&Validation::unwrap), Validation > > WrappedValidationType
Ledger::Seq Seq
void removeTrie(std::scoped_lock< Mutex > const &, NodeID const &nodeID, Validation const &val)
Validations(ValidationParms const &p, beast::AbstractClock< std::chrono::steady_clock > &c, Ts &&... ts)
Constructor.
std::size_t sizeOfSeqEnforcersCache() const
void byLedger(std::scoped_lock< Mutex > const &, ID const &ledgerID, Pre &&pre, F &&f)
Iterate current validations.
Validation::NodeID NodeID
ID getPreferred(Ledger const &curr, Seq minValidSeq)
Get the ID of the preferred working ledger that exceeds a minimum valid ledger sequence number.
std::vector< std::uint32_t > fees(ID const &ledgerID, std::uint32_t baseFee)
Returns fees reported by trusted full validators in the given ledger.
Validation::NodeKey NodeKey
Adaptor::Ledger Ledger
T count_if(T... args)
T duration_cast(T... args)
T emplace_back(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
T insert(T... args)
T make_pair(T... args)
T max_element(T... args)
T max(T... args)
T min(T... args)
std::size_t expire(AgedContainer &c, std::chrono::duration< Rep, Period > const &age)
Expire aged container items past the specified age.
detail::AgedUnorderedContainer< false, true, Key, T, Clock, Hash, KeyEqual, Allocator > AgedUnorderedMap
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool isCurrent(ValidationParms const &p, NetClock::time_point now, NetClock::time_point signTime, NetClock::time_point seenTime)
Whether a validation is still current.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:657
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.
@ Multiple
Multiple validations by a validator for the same ledger.
@ Stale
Not current or was older than current from this node.
Dir::ConstIterator const_iterator
Definition Dir.cpp:16
std::unordered_set< Value, Hash, Pred, Allocator > HashSet
std::unordered_map< Key, Value, Hash, Pred, Allocator > HashMap
T push_back(T... args)
T reserve(T... args)
Timing parameters to control validation staleness and expiration.
Definition Validations.h:36
std::chrono::seconds validationCurrentEarly
Duration pre-close in which validations are acceptable.
Definition Validations.h:63
std::chrono::seconds validationCurrentLocal
Duration a validation remains current after first observed.
Definition Validations.h:55
std::chrono::seconds validationSetExpires
Duration a set of validations for a given ledger hash remain valid.
Definition Validations.h:72
std::chrono::seconds validationFRESHNESS
How long we consider a validation fresh.
Definition Validations.h:83
std::chrono::seconds validationCurrentWall
The number of seconds a validation remains current after its ledger's close time.
Definition Validations.h:46
T tie(T... args)