From dc5ec93207a8bcbb2d8a578347258814eee16014 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Sun, 30 Nov 2025 11:56:22 +0700 Subject: [PATCH] feat: trigger early quorum calculation when VL is fetched Call updateTrusted() immediately when all publisher lists become available in applyListsAndBroadcast(), rather than waiting for beginConsensus(). This allows validations to be trusted within milliseconds of VL fetch instead of waiting 14+ seconds for consensus to start. Also adds debugging logs: - PartialSync journal: untrusted validations during startup - PartialSync journal: checkAccept quorum details - ValidatorSite journal: VL fetch timing --- src/ripple/app/consensus/RCLValidations.cpp | 17 +++++++++++++++++ src/ripple/app/ledger/impl/LedgerMaster.cpp | 13 ++++++++++--- src/ripple/app/misc/impl/ValidatorList.cpp | 10 ++++++++++ src/ripple/app/misc/impl/ValidatorSite.cpp | 12 ++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/ripple/app/consensus/RCLValidations.cpp b/src/ripple/app/consensus/RCLValidations.cpp index 5096621f7..b791064a8 100644 --- a/src/ripple/app/consensus/RCLValidations.cpp +++ b/src/ripple/app/consensus/RCLValidations.cpp @@ -216,6 +216,23 @@ handleNewValidation( app.getLedgerMaster().checkAccept(hash, seq); } } + else + { + // Partial sync debug: only log untrusted validations during startup + // (before we have any validated ledger) + auto [lastHash, lastSeq] = + app.getLedgerMaster().getLastValidatedLedger(); + if (lastSeq == 0) + { + auto jPartialSync = app.journal("PartialSync"); + auto const quorum = app.validators().quorum(); + auto const unlSize = app.validators().count(); + JLOG(jPartialSync.debug()) + << "validation NOT trusted: seq=" << seq << " hash=" << hash + << " unlSize=" << unlSize << " quorum=" << quorum + << " (masterKey=" << (masterKey ? "found" : "none") << ")"; + } + } return; } diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/ripple/app/ledger/impl/LedgerMaster.cpp index 28a9a759f..a5b7f6ddf 100644 --- a/src/ripple/app/ledger/impl/LedgerMaster.cpp +++ b/src/ripple/app/ledger/impl/LedgerMaster.cpp @@ -1012,7 +1012,7 @@ LedgerMaster::checkAccept(uint256 const& hash, std::uint32_t seq) valCount = validations.size(); auto const quorum = app_.validators().quorum(); - JLOG(m_journal.warn()) + JLOG(jPartialSync_.warn()) << "checkAccept: hash=" << hash << " seq=" << seq << " valCount=" << valCount << " quorum=" << quorum << " mLastValidLedger.seq=" << mLastValidLedger.second; @@ -1022,11 +1022,18 @@ LedgerMaster::checkAccept(uint256 const& hash, std::uint32_t seq) std::lock_guard ml(m_mutex); if (seq > mLastValidLedger.second) { - JLOG(m_journal.warn()) - << "checkAccept: setting mLastValidLedger to seq=" << seq; + JLOG(jPartialSync_.warn()) + << "checkAccept: QUORUM REACHED - setting mLastValidLedger" + << " seq=" << seq << " hash=" << hash; mLastValidLedger = std::make_pair(hash, seq); } } + else + { + JLOG(jPartialSync_.debug()) + << "checkAccept: quorum not reached, need " << quorum + << " have " << valCount; + } if (seq == mValidLedgerSeq) return; diff --git a/src/ripple/app/misc/impl/ValidatorList.cpp b/src/ripple/app/misc/impl/ValidatorList.cpp index d17b85c48..8a9d9b828 100644 --- a/src/ripple/app/misc/impl/ValidatorList.cpp +++ b/src/ripple/app/misc/impl/ValidatorList.cpp @@ -895,6 +895,16 @@ ValidatorList::applyListsAndBroadcast( if (good) { networkOPs.clearUNLBlocked(); + // For partial sync: trigger early quorum calculation so + // validations can be trusted before consensus starts + JLOG(j_.warn()) << "All publisher lists available, triggering " + "early updateTrusted for partial sync"; + updateTrusted( + {}, // empty seenValidators - we just need quorum calculated + timeKeeper_.now(), + networkOPs, + overlay, + hashRouter); } } bool broadcast = disposition <= ListDisposition::known_sequence; diff --git a/src/ripple/app/misc/impl/ValidatorSite.cpp b/src/ripple/app/misc/impl/ValidatorSite.cpp index 013d7e96f..2a5de5dfe 100644 --- a/src/ripple/app/misc/impl/ValidatorSite.cpp +++ b/src/ripple/app/misc/impl/ValidatorSite.cpp @@ -166,6 +166,7 @@ ValidatorSite::load( void ValidatorSite::start() { + JLOG(j_.warn()) << "ValidatorSite::start() called"; std::lock_guard l0{sites_mutex_}; std::lock_guard l1{state_mutex_}; if (timer_.expires_at() == clock_type::time_point{}) @@ -218,6 +219,11 @@ ValidatorSite::setTimer( if (next != sites_.end()) { pending_ = next->nextRefresh <= clock_type::now(); + auto delay = std::chrono::duration_cast( + next->nextRefresh - clock_type::now()); + JLOG(j_.warn()) << "ValidatorSite::setTimer() pending=" << pending_ + << " delay=" << delay.count() << "ms" + << " uri=" << next->startingResource->uri; cv_.notify_all(); timer_.expires_at(next->nextRefresh); auto idx = std::distance(sites_.begin(), next); @@ -225,6 +231,10 @@ ValidatorSite::setTimer( this->onTimer(idx, ec); }); } + else + { + JLOG(j_.warn()) << "ValidatorSite::setTimer() no sites configured"; + } } void @@ -339,6 +349,8 @@ ValidatorSite::onRequestTimeout(std::size_t siteIdx, error_code const& ec) void ValidatorSite::onTimer(std::size_t siteIdx, error_code const& ec) { + JLOG(j_.warn()) << "ValidatorSite::onTimer() fired for site " << siteIdx + << " ec=" << ec.message(); if (ec) { // Restart the timer if any errors are encountered, unless the error