mirror of
https://github.com/Xahau/xahaud.git
synced 2026-08-23 00:10:54 +00:00
fix(consensus): skip RNG wait when quorum is impossible and base threshold on active UNL
When fewer participants are present than the quorum threshold, skip the RNG commit wait immediately instead of waiting the full pipeline timeout. Also base the quorum on activeUNLNodeIds_ (UNL Report with fallback) instead of the full trusted key set, so the denominator reflects who is actually active on the network.
This commit is contained in:
@@ -1149,9 +1149,28 @@ RCLConsensus::Adaptor::updateOperatingMode(std::size_t const positions) const
|
||||
std::size_t
|
||||
RCLConsensus::Adaptor::quorumThreshold() const
|
||||
{
|
||||
auto [quorum, trustedKeys] = getQuorumKeys();
|
||||
// Use 80% quorum for RNG commit/reveal
|
||||
return (trustedKeys.size() * 80 + 99) / 100;
|
||||
// Base quorum on the active UNL — the same set used by
|
||||
// isActiveUNLMember() to filter RNG data. This comes from the
|
||||
// UNL Report (in-ledger) with fallback to the trusted key list.
|
||||
// If a node drops off the UNL Report, the denominator shrinks
|
||||
// and quorum becomes achievable with fewer participants.
|
||||
//
|
||||
// TODO: This needs more careful thought. Open questions:
|
||||
// - Should there be a minimum absolute count (e.g. at least 3
|
||||
// committers) to prevent weak entropy from tiny partitions?
|
||||
// - Is 80% the right percentage for RNG, or should it differ
|
||||
// from the tx consensus threshold?
|
||||
// - What happens if the UNL Report is stale and over-counts
|
||||
// active validators? The "impossible quorum" early-exit in
|
||||
// Consensus.h mitigates the worst case (no delay), but the
|
||||
// node still falls back to ZERO entropy.
|
||||
// - On a fresh network with no UNL Report, the fallback is
|
||||
// getTrustedMasterKeys() which includes all configured
|
||||
// validators — possibly including offline ones.
|
||||
auto const base = activeUNLNodeIds_.size();
|
||||
if (base == 0)
|
||||
return 1; // safety: need at least one commit
|
||||
return (base * 80 + 99) / 100;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -1440,20 +1440,38 @@ Consensus<Adaptor>::phaseEstablish()
|
||||
// consensus close logic and nodes inject partial/zero entropy
|
||||
// while others are still collecting — causing ledger mismatches.
|
||||
//
|
||||
// However, if we've already converged on the txSet (which we
|
||||
// have — haveConsensus() passed above) and there aren't enough
|
||||
// participants to ever reach quorum, skip immediately. With
|
||||
// 3 nodes and quorum=3, losing one node means 2/3 commits
|
||||
// forever — waiting 3s per round just delays recovery.
|
||||
//
|
||||
// NOTE: Late-joining nodes (e.g. restarting after a crash)
|
||||
// cannot help here. They enter the round as proposing=false
|
||||
// and onClose() skips commitment generation for non-proposers.
|
||||
// It takes at least one full round of observing before
|
||||
// consensus promotes them to proposing. So waiting beyond
|
||||
// a few seconds is pointless — use rngPIPELINE_TIMEOUT (3s)
|
||||
// rather than ledgerMAX_CONSENSUS (10s) to avoid penalizing
|
||||
// the recovery path.
|
||||
// consensus promotes them to proposing.
|
||||
{
|
||||
bool timeout =
|
||||
result_->roundTime.read() > parms.rngPIPELINE_TIMEOUT;
|
||||
if (!timeout)
|
||||
return; // Wait for more commits
|
||||
// On timeout: fall through to normal close (zero entropy)
|
||||
// participants = peers + ourselves
|
||||
auto const participants = currPeerPositions_.size() + 1;
|
||||
auto const threshold = adaptor_.quorumThreshold();
|
||||
bool const impossible = participants < threshold;
|
||||
|
||||
if (impossible)
|
||||
{
|
||||
JLOG(j_.debug())
|
||||
<< "RNG: skipping commit wait (participants="
|
||||
<< participants << " < threshold=" << threshold << ")";
|
||||
// Fall through to close with zero entropy
|
||||
}
|
||||
else
|
||||
{
|
||||
bool timeout =
|
||||
result_->roundTime.read() > parms.rngPIPELINE_TIMEOUT;
|
||||
if (!timeout)
|
||||
return; // Wait for more commits
|
||||
// On timeout: fall through to normal close (zero entropy)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (estState_ == EstablishState::ConvergingCommit)
|
||||
|
||||
Reference in New Issue
Block a user