From 5f70e5259c02af97e3dc0eeb9e9958baa01c4c2f Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Thu, 9 Apr 2026 15:35:00 +0700 Subject: [PATCH] fix(rng): use entropySetMap for shouldZeroEntropy and sfEntropyCount The H2 entropy fix switched the digest computation to entropySetMap_ but shouldZeroEntropy() and sfEntropyCount still used pendingReveals_. Since pendingReveals_ can diverge from the published entropySetMap_ (late reveals mutate it after the map hash is published), two nodes agreeing on the same entropySetHash could still build different ttCONSENSUS_ENTROPY pseudo-transactions. Now shouldZeroEntropy() checks entropySetMap_ leaf count when the map is available, and sfEntropyCount uses the map's leaf count. Both fall back to pendingReveals_ only during pipeline stages before the map is built. --- .../app/consensus/ConsensusExtensions.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/xrpld/app/consensus/ConsensusExtensions.cpp b/src/xrpld/app/consensus/ConsensusExtensions.cpp index 317c2ba10..7142d87d1 100644 --- a/src/xrpld/app/consensus/ConsensusExtensions.cpp +++ b/src/xrpld/app/consensus/ConsensusExtensions.cpp @@ -168,7 +168,18 @@ ConsensusExtensions::hasAnyReveals() const bool ConsensusExtensions::shouldZeroEntropy() const { - return entropyFailed_ || pendingReveals_.empty() || + if (entropyFailed_) + return true; + + // Use entropySetMap_ as the canonical source when available, + // falling back to pendingReveals_ during pipeline stages + // before the map is built (e.g. ConvergingReveal timeout checks). + if (entropySetMap_) + { + auto const leafCount = entropySetMap_->leafCount(); + return leafCount == 0 || leafCount < quorumThreshold(); + } + return pendingReveals_.empty() || pendingReveals_.size() < quorumThreshold(); } @@ -1180,7 +1191,10 @@ ConsensusExtensions::onPreBuild(CanonicalTXSet& retriableTxs, LedgerIndex seq) auto const entropyCount = static_cast( app_.config().standalone() ? 20 // synthetic: high enough for Hook APIs (need >= 5) - : (shouldZeroEntropy() ? 0 : pendingReveals_.size())); + : (shouldZeroEntropy() + ? 0 + : (entropySetMap_ ? entropySetMap_->leafCount() + : pendingReveals_.size()))); STTx tx(ttCONSENSUS_ENTROPY, [&](auto& obj) { obj.setFieldU32(sfLedgerSequence, seq); obj.setAccountID(sfAccount, AccountID{});