From eca887c66ec2ab4f2e9de51c90c01d89452a9e2c Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Tue, 31 Mar 2026 16:38:21 +0100 Subject: [PATCH] feat(telemetry): add 7-day validation agreement window to ValidationTracker Add window7d_ deque, agreementPct7d(), agreements7d(), missed7d() to match the external xrpl-validator-dashboard's 7-day agreement tracking. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/xrpld/telemetry/ValidationTracker.h | 22 ++++++++++++- .../telemetry/detail/ValidationTracker.cpp | 33 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/xrpld/telemetry/ValidationTracker.h b/src/xrpld/telemetry/ValidationTracker.h index 462f309ff4..e1c3bf71e0 100644 --- a/src/xrpld/telemetry/ValidationTracker.h +++ b/src/xrpld/telemetry/ValidationTracker.h @@ -139,6 +139,12 @@ public: double agreementPct24h() const; + /** Agreement percentage over the last 7 days. + * @return Percentage [0.0, 100.0], or 0.0 if no data. + */ + double + agreementPct7d() const; + /** @} */ /** @name Rolling-window count getters */ @@ -160,6 +166,14 @@ public: uint64_t missed24h() const; + /** Number of agreements in the 7-day window. */ + uint64_t + agreements7d() const; + + /** Number of misses in the 7-day window. */ + uint64_t + missed7d() const; + /** @} */ /** @name Lifetime totals (atomic, lock-free reads) */ @@ -223,7 +237,10 @@ private: /// Duration of the long rolling window. static constexpr auto kWindow24h = std::chrono::hours(24); - /// Protects pending_, window1h_, and window24h_. + /// Duration of the extended rolling window (7 days). + static constexpr auto kWindow7d = std::chrono::hours(168); + + /// Protects pending_, window1h_, window24h_, and window7d_. mutable std::mutex mutex_; /// Pending ledger events indexed by ledger hash. @@ -235,6 +252,9 @@ private: /// Sliding window of reconciled events (last 24 hours). std::deque window24h_; + /// Sliding window of reconciled events (last 7 days). + std::deque window7d_; + /// Lifetime count of agreements. std::atomic totalAgreements_{0}; diff --git a/src/xrpld/telemetry/detail/ValidationTracker.cpp b/src/xrpld/telemetry/detail/ValidationTracker.cpp index c5dfae2d27..8167b2c51b 100644 --- a/src/xrpld/telemetry/detail/ValidationTracker.cpp +++ b/src/xrpld/telemetry/detail/ValidationTracker.cpp @@ -62,6 +62,7 @@ ValidationTracker::reconcile() WindowEvent we{now, evt.ledgerHash, evt.agreed}; window1h_.push_back(we); window24h_.push_back(we); + window7d_.push_back(we); } else if ( evt.reconciled && !evt.agreed && evt.weValidated && evt.networkValidated && @@ -75,6 +76,7 @@ ValidationTracker::reconcile() // Flip the corresponding window entries from miss to agreement. repairWindowEntry(window1h_, evt.ledgerHash); repairWindowEntry(window24h_, evt.ledgerHash); + repairWindowEntry(window7d_, evt.ledgerHash); } } @@ -92,6 +94,10 @@ ValidationTracker::evictStaleWindows(TimePoint now) auto const cutoff24h = now - kWindow24h; while (!window24h_.empty() && window24h_.front().time < cutoff24h) window24h_.pop_front(); + + auto const cutoff7d = now - kWindow7d; + while (!window7d_.empty() && window7d_.front().time < cutoff7d) + window7d_.pop_front(); } void @@ -186,6 +192,33 @@ ValidationTracker::missed24h() const window24h_.begin(), window24h_.end(), [](auto const& e) { return !e.agreed; })); } +double +ValidationTracker::agreementPct7d() const +{ + std::lock_guard lock(mutex_); + if (window7d_.empty()) + return 0.0; + auto const agreed = static_cast( + std::count_if(window7d_.begin(), window7d_.end(), [](auto const& e) { return e.agreed; })); + return (agreed / static_cast(window7d_.size())) * 100.0; +} + +uint64_t +ValidationTracker::agreements7d() const +{ + std::lock_guard lock(mutex_); + return static_cast( + std::count_if(window7d_.begin(), window7d_.end(), [](auto const& e) { return e.agreed; })); +} + +uint64_t +ValidationTracker::missed7d() const +{ + std::lock_guard lock(mutex_); + return static_cast( + std::count_if(window7d_.begin(), window7d_.end(), [](auto const& e) { return !e.agreed; })); +} + uint64_t ValidationTracker::totalAgreements() const {