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
327 ID,
332
333 // Partial and full validations indexed by sequence
335 Seq,
340
341 // A range [low_, high_) of validations to keep from expire
343 {
346 };
348
349 // Represents the ancestry of validated ledgers
351
352 // Last (validated) ledger successfully acquired. If in this map, it is
353 // accounted for in the trie.
355
356 // Set of ledgers being acquired from the network
358
359 // Parameters to determine validation staleness
361
362 // Adaptor instance
363 // Is NOT managed by the mutex_ above
364 Adaptor adaptor_;
365
366private:
367 // Remove support of a validated ledger
368 void
369 removeTrie(std::scoped_lock<Mutex> const&, NodeID const& nodeID, Validation const& val)
370 {
371 {
372 auto it = acquiring_.find(std::make_pair(val.seq(), val.ledgerID()));
373 if (it != acquiring_.end())
374 {
375 it->second.erase(nodeID);
376 if (it->second.empty())
377 acquiring_.erase(it);
378 }
379 }
380 {
381 auto it = lastLedger_.find(nodeID);
382 if (it != lastLedger_.end() && it->second.id() == val.ledgerID())
383 {
384 trie_.remove(it->second);
385 lastLedger_.erase(nodeID);
386 }
387 }
388 }
389
390 // Check if any pending acquire ledger requests are complete
391 void
393 {
394 for (auto it = acquiring_.begin(); it != acquiring_.end();)
395 {
396 if (std::optional<Ledger> ledger = adaptor_.acquire(it->first.second))
397 {
398 for (NodeID const& nodeID : it->second)
399 updateTrie(lock, nodeID, *ledger);
400
401 it = acquiring_.erase(it);
402 }
403 else
404 {
405 ++it;
406 }
407 }
408 }
409
410 // Update the trie to reflect a new validated ledger
411 void
412 updateTrie(std::scoped_lock<Mutex> const&, NodeID const& nodeID, Ledger ledger)
413 {
414 auto const [it, inserted] = lastLedger_.emplace(nodeID, ledger);
415 if (!inserted)
416 {
417 trie_.remove(it->second);
418 it->second = ledger;
419 }
420 trie_.insert(ledger);
421 }
422
437 void
439 std::scoped_lock<Mutex> const& lock,
440 NodeID const& nodeID,
441 Validation const& val,
443 {
444 XRPL_ASSERT(val.trusted(), "xrpl::Validations::updateTrie : trusted input validation");
445
446 // Clear any prior acquiring ledger for this node
447 if (prior)
448 {
449 auto it = acquiring_.find(*prior);
450 if (it != acquiring_.end())
451 {
452 it->second.erase(nodeID);
453 if (it->second.empty())
454 acquiring_.erase(it);
455 }
456 }
457
458 checkAcquired(lock);
459
460 std::pair<Seq, ID> const valPair{val.seq(), val.ledgerID()};
461 auto it = acquiring_.find(valPair);
462 if (it != acquiring_.end())
463 {
464 it->second.insert(nodeID);
465 }
466 else
467 {
468 if (std::optional<Ledger> ledger = adaptor_.acquire(val.ledgerID()))
469 {
470 updateTrie(lock, nodeID, *ledger);
471 }
472 else
473 {
474 acquiring_[valPair].insert(nodeID);
475 }
476 }
477 }
478
491 template <class F>
492 auto
494 {
495 // Call current to flush any stale validations
496 current(lock, [](auto) {}, [](auto, auto) {});
497 checkAcquired(lock);
498 return f(trie_);
499 }
500
517
518 template <class Pre, class F>
519 void
520 current(std::scoped_lock<Mutex> const& lock, Pre&& pre, F&& f)
521 {
522 NetClock::time_point const t = adaptor_.now();
523 pre(current_.size());
524 auto it = current_.begin();
525 while (it != current_.end())
526 {
527 // Check for staleness
528 if (!isCurrent(parms_, t, it->second.signTime(), it->second.seenTime()))
529 {
530 removeTrie(lock, it->first, it->second);
531 it = current_.erase(it);
532 }
533 else
534 {
535 auto cit = typename decltype(current_)::const_iterator{it};
536 // contains a live record
537 f(cit->first, cit->second);
538 ++it;
539 }
540 }
541 }
542
556 template <class Pre, class F>
557 void
558 byLedger(std::scoped_lock<Mutex> const&, ID const& ledgerID, Pre&& pre, F&& f)
559 {
560 auto it = byLedger_.find(ledgerID);
561 if (it != byLedger_.end())
562 {
563 // Update set time since it is being used
564 byLedger_.touch(it);
565 pre(it->second.size());
566 for (auto const& [key, val] : it->second)
567 f(key, val);
568 }
569 }
570
571public:
579 template <class... Ts>
581 ValidationParms const& p,
583 Ts&&... ts)
584 : byLedger_(c), bySequence_(c), parms_(p), adaptor_(std::forward<Ts>(ts)...)
585 {
586 }
587
591 Adaptor const&
592 adaptor() const
593 {
594 return adaptor_;
595 }
596
600 ValidationParms const&
601 parms() const
602 {
603 return parms_;
604 }
605
614 bool
616 {
617 std::scoped_lock const lock{mutex_};
618 return localSeqEnforcer_(byLedger_.clock().now(), s, parms_);
619 }
620
631 add(NodeID const& nodeID, Validation const& val)
632 {
633 if (!isCurrent(parms_, adaptor_.now(), val.signTime(), val.seenTime()))
634 return ValStatus::Stale;
635
636 {
637 std::scoped_lock const lock{mutex_};
638
639 // Check that validation sequence is greater than any non-expired
640 // validations sequence from that validator; if it's not, perform
641 // additional work to detect Byzantine validations
642 auto const now = byLedger_.clock().now();
643
644 auto const [seqit, seqinserted] = bySequence_[val.seq()].emplace(nodeID, val);
645
646 if (!seqinserted)
647 {
648 // Check if the entry we're already tracking was signed
649 // long enough ago that we can disregard it.
650 auto const diff = std::max(seqit->second.signTime(), val.signTime()) -
651 std::min(seqit->second.signTime(), val.signTime());
652
653 if (diff > parms_.validationCurrentWall &&
654 val.signTime() > seqit->second.signTime())
655 seqit->second = val;
656 }
657
658 // Enforce monotonically increasing sequences for validations
659 // by a given node, and run the active Byzantine detector:
660 if (auto& enf = seqEnforcers_[nodeID]; !enf(now, val.seq(), parms_))
661 {
662 // If the validation is for the same sequence as one we are
663 // tracking, check it closely:
664 if (seqit->second.seq() == val.seq())
665 {
666 // Two validations for the same sequence but for different
667 // ledgers. This could be the result of misconfiguration
668 // but it can also mean a Byzantine validator.
669 if (seqit->second.ledgerID() != val.ledgerID())
671
672 // Two validations for the same sequence and for the same
673 // ledger with different sign times. This could be the
674 // result of a misconfiguration but it can also mean a
675 // Byzantine validator.
676 if (seqit->second.signTime() != val.signTime())
678
679 // Two validations for the same sequence but with different
680 // cookies. This is probably accidental misconfiguration.
681 if (seqit->second.cookie() != val.cookie())
682 return ValStatus::Multiple;
683 }
684
685 return ValStatus::BadSeq;
686 }
687
688 byLedger_[val.ledgerID()].insert_or_assign(nodeID, val);
689
690 auto const [it, inserted] = current_.emplace(nodeID, val);
691 if (!inserted)
692 {
693 // Replace existing only if this one is newer
694 Validation const& oldVal = it->second;
695 if (val.signTime() > oldVal.signTime())
696 {
697 std::pair<Seq, ID> old(oldVal.seq(), oldVal.ledgerID());
698 it->second = val;
699 if (val.trusted())
700 updateTrie(lock, nodeID, val, old);
701 }
702 else
703 {
704 return ValStatus::Stale;
705 }
706 }
707 else if (val.trusted())
708 {
709 updateTrie(lock, nodeID, val, std::nullopt);
710 }
711 }
712
713 return ValStatus::Current;
714 }
715
722 void
723 setSeqToKeep(Seq const& low, Seq const& high)
724 {
725 std::scoped_lock const lock{mutex_};
726 XRPL_ASSERT(low < high, "xrpl::Validations::setSeqToKeep : valid inputs");
727 toKeep_ = {low, high};
728 }
729
736 void
738 {
739 auto const start = std::chrono::steady_clock::now();
740 {
741 std::scoped_lock const lock{mutex_};
742 if (toKeep_)
743 {
744 // We only need to refresh the keep range when it's just about
745 // to expire. Track the next time we need to refresh.
746 static std::chrono::steady_clock::time_point kRefreshTime;
747 if (auto const now = byLedger_.clock().now(); kRefreshTime <= now)
748 {
749 // The next refresh time is shortly before the expiration
750 // time from now.
751 kRefreshTime = now + parms_.validationSetExpires - parms_.validationFRESHNESS;
752
753 for (auto i = byLedger_.begin(); i != byLedger_.end(); ++i)
754 {
755 auto const& validationMap = i->second;
756 if (!validationMap.empty())
757 {
758 auto const seq = validationMap.begin()->second.seq();
759 if (toKeep_->low <= seq && seq < toKeep_->high)
760 {
761 byLedger_.touch(i);
762 }
763 }
764 }
765
766 for (auto i = bySequence_.begin(); i != bySequence_.end(); ++i)
767 {
768 if (toKeep_->low <= i->first && i->first < toKeep_->high)
769 {
770 bySequence_.touch(i);
771 }
772 }
773 }
774 }
775
776 beast::expire(byLedger_, parms_.validationSetExpires);
777 beast::expire(bySequence_, parms_.validationSetExpires);
778 }
779 JLOG(j.debug()) << "Validations sets sweep lock duration "
782 .count()
783 << "ms";
784 }
785
796 void
797 trustChanged(hash_set<NodeID> const& added, hash_set<NodeID> const& removed)
798 {
799 std::scoped_lock const lock{mutex_};
800
801 for (auto& [nodeId, validation] : current_)
802 {
803 if (added.find(nodeId) != added.end())
804 {
805 validation.setTrusted();
806 updateTrie(lock, nodeId, validation, std::nullopt);
807 }
808 else if (removed.find(nodeId) != removed.end())
809 {
810 validation.setUntrusted();
811 removeTrie(lock, nodeId, validation);
812 }
813 }
814
815 for (auto& [_, validationMap] : byLedger_)
816 {
817 (void)_;
818 for (auto& [nodeId, validation] : validationMap)
819 {
820 if (added.find(nodeId) != added.end())
821 {
822 validation.setTrusted();
823 }
824 else if (removed.find(nodeId) != removed.end())
825 {
826 validation.setUntrusted();
827 }
828 }
829 }
830 }
831
834 {
835 std::scoped_lock const lock{mutex_};
836 return trie_.getJson();
837 }
838
853 getPreferred(Ledger const& curr)
854 {
855 std::scoped_lock const lock{mutex_};
856 std::optional<SpanTip<Ledger>> preferred = withTrie(lock, [this](LedgerTrie<Ledger>& trie) {
857 return trie.getPreferred(localSeqEnforcer_.largest());
858 });
859 // No trusted validations to determine branch
860 if (!preferred)
861 {
862 // fall back to majority over acquiring ledgers
863 auto it = std::ranges::max_element(acquiring_, [](auto const& a, auto const& b) {
864 std::pair<Seq, ID> const& aKey = a.first;
865 typename hash_set<NodeID>::size_type const& aSize = a.second.size();
866 std::pair<Seq, ID> const& bKey = b.first;
867 typename hash_set<NodeID>::size_type const& bSize = b.second.size();
868 // order by number of trusted peers validating that ledger
869 // break ties with ledger ID
870 return std::tie(aSize, aKey.second) < std::tie(bSize, bKey.second);
871 });
872 if (it != acquiring_.end())
873 return it->first;
874 return std::nullopt;
875 }
876
877 // If we are the parent of the preferred ledger, stick with our
878 // current ledger since we might be about to generate it
879 if (preferred->seq == curr.seq() + Seq{1} && preferred->ancestor(curr.seq()) == curr.id())
880 return std::make_pair(curr.seq(), curr.id());
881
882 // A ledger ahead of us is preferred regardless of whether it is
883 // a descendant of our working ledger or it is on a different chain
884 if (preferred->seq > curr.seq())
885 return std::make_pair(preferred->seq, preferred->id);
886
887 // Only switch to earlier or same sequence number
888 // if it is a different chain.
889 if (curr[preferred->seq] != preferred->id)
890 return std::make_pair(preferred->seq, preferred->id);
891
892 // Stick with current ledger
893 return std::make_pair(curr.seq(), curr.id());
894 }
895
906 ID
907 getPreferred(Ledger const& curr, Seq minValidSeq)
908 {
910 if (preferred && preferred->first >= minValidSeq)
911 return preferred->second;
912 return curr.id();
913 }
914
932 ID
933 getPreferredLCL(Ledger const& lcl, Seq minSeq, hash_map<ID, std::uint32_t> const& peerCounts)
934 {
936
937 // Trusted validations exist, but stick with local preferred ledger if
938 // preferred is in the past
939 if (preferred)
940 return (preferred->first >= minSeq) ? preferred->second : lcl.id();
941
942 // Otherwise, rely on peer ledgers
943 auto it = std::ranges::max_element(peerCounts, [](auto const& a, auto const& b) {
944 // Prefer larger counts, then larger ids on ties
945 // (max_element expects this to return true if a < b)
946 return std::tie(a.second, a.first) < std::tie(b.second, b.first);
947 });
948
949 if (it != peerCounts.end())
950 return it->first;
951 return lcl.id();
952 }
953
967 getNodesAfter(Ledger const& ledger, ID const& ledgerID)
968 {
969 std::scoped_lock const lock{mutex_};
970
971 // Use trie if ledger is the right one
972 if (ledger.id() == ledgerID)
973 {
974 return withTrie(lock, [&ledger](LedgerTrie<Ledger>& trie) {
975 return trie.branchSupport(ledger) - trie.tipSupport(ledger);
976 });
977 }
978
979 // Count parent ledgers as fallback
980 return std::ranges::count_if(lastLedger_, [&ledgerID](auto const& it) {
981 auto const& curr = it.second;
982 return curr.seq() > Seq{0} && curr[curr.seq() - Seq{1}] == ledgerID;
983 });
984 }
985
993 {
995 std::scoped_lock const lock{mutex_};
996 current(
997 lock,
998 [&](std::size_t numValidations) { ret.reserve(numValidations); },
999 [&](NodeID const&, Validation const& v) {
1000 if (v.trusted() && v.full())
1001 ret.push_back(v.unwrap());
1002 });
1003 return ret;
1004 }
1005
1011 auto
1013 {
1014 hash_set<NodeID> ret;
1015 std::scoped_lock const lock{mutex_};
1016 current(
1017 lock,
1018 [&](std::size_t numValidations) { ret.reserve(numValidations); },
1019 [&](NodeID const& nid, Validation const&) { ret.insert(nid); });
1020
1021 return ret;
1022 }
1023
1031 numTrustedForLedger(ID const& ledgerID)
1032 {
1033 std::size_t count = 0;
1034 std::scoped_lock const lock{mutex_};
1035 byLedger(
1036 lock,
1037 ledgerID,
1038 [&](std::size_t) {}, // nothing to reserve
1039 [&](NodeID const&, Validation const& v) {
1040 if (v.trusted() && v.full())
1041 ++count;
1042 });
1043 return count;
1044 }
1045
1054 getTrustedForLedger(ID const& ledgerID, Seq const& seq)
1055 {
1057 std::scoped_lock const lock{mutex_};
1058 byLedger(
1059 lock,
1060 ledgerID,
1061 [&](std::size_t numValidations) { res.reserve(numValidations); },
1062 [&](NodeID const&, Validation const& v) {
1063 if (v.trusted() && v.full() && v.seq() == seq)
1064 res.emplace_back(v.unwrap());
1065 });
1066
1067 return res;
1068 }
1069
1078 fees(ID const& ledgerID, std::uint32_t baseFee)
1079 {
1081 std::scoped_lock const lock{mutex_};
1082 byLedger(
1083 lock,
1084 ledgerID,
1085 [&](std::size_t numValidations) { res.reserve(numValidations); },
1086 [&](NodeID const&, Validation const& v) {
1087 if (v.trusted() && v.full())
1088 {
1089 std::optional<std::uint32_t> loadFee = v.loadFee();
1090 if (loadFee)
1091 {
1092 res.push_back(*loadFee);
1093 }
1094 else
1095 {
1096 res.push_back(baseFee);
1097 }
1098 }
1099 });
1100 return res;
1101 }
1102
1106 void
1108 {
1109 std::scoped_lock const lock{mutex_};
1110 current_.clear();
1111 }
1112
1130 laggards(Seq const seq, hash_set<NodeKey>& trustedKeys)
1131 {
1133
1134 current(
1136 [](std::size_t) {},
1137 [&](NodeID const&, Validation const& v) {
1138 if (adaptor_.now() < v.seenTime() + parms_.validationFRESHNESS &&
1139 trustedKeys.find(v.key()) != trustedKeys.end())
1140 {
1141 trustedKeys.erase(v.key());
1142 if (seq > v.seq())
1143 ++laggards;
1144 }
1145 });
1146
1147 return laggards;
1148 }
1149
1152 {
1153 std::scoped_lock const lock{mutex_};
1154 return current_.size();
1155 }
1156
1159 {
1160 std::scoped_lock const lock{mutex_};
1161 return seqEnforcers_.size();
1162 }
1163
1166 {
1167 std::scoped_lock const lock{mutex_};
1168 return byLedger_.size();
1169 }
1170
1173 {
1174 std::scoped_lock const lock{mutex_};
1175 return bySequence_.size();
1176 }
1177};
1178
1179} // 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.
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.
uint256 ledgerID() const
Validated ledger's hash.
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)
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.
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.
auto getCurrentNodeIDs() -> hash_set< NodeID >
Get the set of node ids associated with current validations.
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.
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
void trustChanged(hash_set< NodeID > const &added, hash_set< NodeID > const &removed)
Update trust status of validations.
ValidationParms const & parms() const
Return the validation timing parameters.
void checkAcquired(std::scoped_lock< Mutex > const &lock)
hash_map< NodeID, Validation > current_
hash_map< NodeID, SeqEnforcer< Seq > > seqEnforcers_
Adaptor::Mutex Mutex
Adaptor const & adaptor() const
Return the adaptor instance.
hash_map< NodeID, Ledger > lastLedger_
beast::aged_unordered_map< Seq, hash_map< NodeID, Validation >, std::chrono::steady_clock, beast::Uhash<> > bySequence_
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.
beast::aged_unordered_map< ID, hash_map< NodeID, Validation >, std::chrono::steady_clock, beast::Uhash<> > byLedger_
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.
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
std::size_t laggards(Seq const seq, hash_set< NodeKey > &trustedKeys)
Return quantity of lagging proposers, and remove online proposers for purposes of evaluating whether ...
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
hash_map< std::pair< Seq, ID >, hash_set< NodeID > > acquiring_
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 > aged_unordered_map
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::unordered_set< Value, Hash, Pred, Allocator > hash_set
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
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_map< Key, Value, Hash, Pred, Allocator > hash_map
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)