diff --git a/src/xrpld/app/consensus/ConsensusExtensionsDesign.md b/src/xrpld/app/consensus/ConsensusExtensionsDesign.md index 898d0a281..a56073e6d 100644 --- a/src/xrpld/app/consensus/ConsensusExtensionsDesign.md +++ b/src/xrpld/app/consensus/ConsensusExtensionsDesign.md @@ -192,6 +192,11 @@ Export sig convergence runs in parallel with RNG. An export-side convergence failure must not change RNG semantics; an RNG fallback must not make export unsafe. Each feature has its own gate and fallback. +Accept-time cleanup must preserve Export state through `buildLCL` whenever +`featureExport` is enabled. RNG-disabled does not mean extensions-disabled: +`ttEXPORT` still needs the round's export sidecar convergence state when it +applies. + CSF consensus tests model the export sidecar gate directly. Testnet scenarios under `.testnet/scenarios/export/` cover live-node Export+CE behavior and the Export-only unanimity mode. diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 064e36aa7..3be828a70 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -587,13 +587,14 @@ RCLConsensus::Adaptor::doAccept( } //@@start auxiliary-pre-build-injection - // Inject consensus entropy pseudo-transaction (if amendment enabled) - // This must happen before buildLCL so the entropy tx is in the ledger + // Inject consensus entropy pseudo-transaction (if amendment enabled). + // Export-only rounds still need extension state preserved through buildLCL + // so ttEXPORT can observe exportSigSetHash convergence at apply time. //@@start accept-time-cleanup-disabled - if (prevLedger.ledger_->rules().enabled(featureConsensusEntropy)) + if (ce().rngEnabled()) ce().onPreBuild(retriableTxs, prevLedger.seq() + 1); - else - ce().clearRngState(); // CE disabled — clear extension state now + else if (!ce().exportEnabled()) + ce().clearRngState(); //@@end accept-time-cleanup-disabled auto built = buildLCL(