From a95306142ef439930ad6f52b3dd3916b28027ae3 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Mon, 15 Jun 2026 17:48:53 +0700 Subject: [PATCH] =?UTF-8?q?test(rng):=20tier-2=20mint=20sim=20=E2=80=94=20?= =?UTF-8?q?in-band=20cohort=20at=20n=3D6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 6 validators is the smallest non-degenerate tier-2 size (f=1, one-wide band {4}: tier2=4, quorum=5). Isolate 2 so the surviving 4-cohort is below the 80% quorum but at the tier-2 floor; it mints participant_aligned entropy (count 4), and all four agree on the same non-zero digest with branches==1 — no hang, no fork. Distributed confirmation of the selector ladder the unit tests already cover. --- src/test/consensus/ConsensusRng_test.cpp | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/test/consensus/ConsensusRng_test.cpp b/src/test/consensus/ConsensusRng_test.cpp index 75bf53bd0..91fdbf17d 100644 --- a/src/test/consensus/ConsensusRng_test.cpp +++ b/src/test/consensus/ConsensusRng_test.cpp @@ -219,6 +219,57 @@ public: } } + void + testRngTier2MintByBandCohort() + { + using namespace csf; + using namespace std::chrono; + + testcase("RNG tier 2 minted by in-band aligned cohort"); + + // 6 validators — the smallest NON-degenerate tier-2 size: f=1 (one + // tolerated fault) and a one-wide band {4} (tier2=4, quorum=5). Isolate + // 2 so the surviving 4-validator cohort is below the 80% quorum but at + // the tier-2 floor. It mints participant_aligned entropy, and all four + // agree on the same non-zero digest — no hang, no fork. + ConsensusParms const parms{}; + Sim sim; + + PeerGroup cohort = sim.createGroup(4); + PeerGroup isolated = sim.createGroup(2); + PeerGroup network = cohort + isolated; + + for (Peer* peer : network) + peer->ce().enableRngConsensus_ = true; + + network.trust(network); + network.connect( + network, round(0.2 * parms.ledgerGRANULARITY)); + sim.run(1); + + cohort.disconnect(isolated); + isolated.disconnect(cohort); + cohort.connect( + cohort, round(0.2 * parms.ledgerGRANULARITY)); + + sim.run(2); + + if (BEAST_EXPECT(sim.synchronized(cohort))) + { + BEAST_EXPECT(sim.branches(cohort) == 1); + for (Peer const* peer : cohort) + { + BEAST_EXPECT(!peer->ce().lastEntropyWasFallback_); + BEAST_EXPECT(peer->ce().lastEntropyTier_ == 2); + BEAST_EXPECT(peer->ce().lastEntropyCount_ == 4); + BEAST_EXPECT(peer->ce().lastEntropyDigest_ != uint256{}); + BEAST_EXPECT( + peer->ce().lastEntropyDigest_ == + cohort[0]->ce().lastEntropyDigest_); + } + } + } + void testRngTimeoutWithPartialQuorum() { @@ -994,6 +1045,7 @@ public: RUN(testRngCommitRevealConvergesWithTransactions); RUN(testRngQuorumImpossibleFallsToTier2); RUN(testRngPersistentLossDoesNotShrinkQuorum); + RUN(testRngTier2MintByBandCohort); RUN(testRngTimeoutWithPartialQuorum); RUN(testRngCommitSetConflictForcesFallback); RUN(testRngObserverDoesNotExpectSelfCommit);