Pin extension apply to accepted sidecar roots

Require entropy injection and export apply to consume only sidecar roots accepted by their convergence gates. Local timeout state and later collector growth no longer participate in closed-ledger material once a sidecar root is accepted.

Also guard RCLConsensus::extensionsBusy() under the consensus mutex, cap exported multisig signer arrays to the protocol maximum after canonical signer sorting, and document the remaining accept-vs-timeout liveness tradeoff.

Add regressions for unaccepted export sidecar roots, late export collector mutation, entropy accepted-root handling, exported signer caps, and CSF accepted-sidecar behavior.
This commit is contained in:
Nicholas Dudfield
2026-06-26 16:50:19 +07:00
parent 229eb5b573
commit d091ebfb7e
11 changed files with 273 additions and 37 deletions

View File

@@ -811,10 +811,12 @@ struct Export_test : public beast::unit_test::suite
txHash, valPK, originalSig, applySeq);
auto const agreedHash = ce.buildExportSigSet(applySeq);
BEAST_EXPECT(ce.isSidecarSet(agreedHash));
ce.acceptExportSigSet(agreedHash);
ce.setExportSigConvergenceFailed();
// Simulate an asynchronous collector mutation after sidecar agreement.
// A bad revert to the live collector at apply would assemble this late
// signature and write a different shadow-ticket hash.
// Closed-ledger apply must derive the signature snapshot from the
// agreed sidecar, not from the live collector or a local timeout flag.
std::uint8_t const lateBytes[] = {9, 8, 7};
Buffer const lateSig{lateBytes, sizeof(lateBytes)};
ce.exportSigCollector().addVerifiedSignature(
@@ -895,6 +897,7 @@ struct Export_test : public beast::unit_test::suite
txHash, valPK, sig, applySeq);
auto const agreedHash = ce.buildExportSigSet(applySeq);
BEAST_EXPECT(ce.isSidecarSet(agreedHash));
ce.acceptExportSigSet(agreedHash);
auto const parent = env.app().getLedgerMaster().getClosedLedger();
auto next = std::make_shared<Ledger>(
@@ -964,6 +967,7 @@ struct Export_test : public beast::unit_test::suite
txHash, valPK, sig, applySeq);
auto const agreedHash = ce.buildExportSigSet(applySeq);
BEAST_EXPECT(ce.isSidecarSet(agreedHash));
ce.acceptExportSigSet(agreedHash);
}
auto next = std::make_shared<Ledger>(