Skip to content

Commit 9526033

Browse files
committed
[deliverorderer] Add test scenarios
Signed-off-by: Liran Funaro <liran.funaro@gmail.com>
1 parent 4322e38 commit 9526033

2 files changed

Lines changed: 430 additions & 0 deletions

File tree

utils/deliverorderer/orderer_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,52 @@ func TestOrdererDeliverBFT(t *testing.T) {
564564
}
565565
}
566566

567+
// TestOrdererDeliverBFTRepeatedPromotionProgresses is an end-to-end guard for the
568+
// "cascading suspicion can halt block delivery" bug (#632). With real gRPC streams, header-only
569+
// streams continuously race ahead of the data stream, so a freshly promoted data source typically
570+
// already has header-only blocks queued. Before the fix, such a stale header-only block from the
571+
// promoted source was processed as a (payload-less) data block, immediately re-suspecting it and
572+
// promoting yet another source — a cascade that stalls delivery.
573+
//
574+
// Here we force the current data source to withhold the next block every round (a short grace
575+
// period promotes a new source quickly). Delivery must keep progressing across repeated
576+
// promotions rather than stalling.
577+
func TestOrdererDeliverBFTRepeatedPromotionProgresses(t *testing.T) {
578+
t.Parallel()
579+
e := newDeliverOrdererTestEnv(t, deliverOrdererTestEnvParams{
580+
ftMode: ordererdial.BFT,
581+
tlsMode: connection.NoneTLSMode,
582+
})
583+
// A short grace period makes suspicion + promotion happen quickly.
584+
e.deliveryParams.SuspicionGracePeriodPerBlock = 100 * time.Millisecond
585+
stopDelivery := e.startDelivery(t)
586+
defer stopDelivery()
587+
e.waitForDeliveryOfConfigBlock(t)
588+
require.Len(t, e.PartyStates, 3)
589+
590+
//nolint:gosec // party IDs are small, non-negative values.
591+
prev := uint32(test.GetIntMetricValue(t, e.deliveryParams.Metrics.CurrentDataSourceID))
592+
for range 4 {
593+
expectedBlockNum := e.PrevBlock.Header.Number + 1
594+
// Withhold the next full data block only from the current source, forcing a promotion.
595+
for _, p := range e.PartyStates {
596+
p.HoldFromBlock.Store(0)
597+
}
598+
e.PartyStates[prev].HoldFromBlock.Store(expectedBlockNum)
599+
600+
b := e.submit(t)
601+
require.NotEqual(t, prev, b.SourceID, "delivery must rotate away from the withholding source")
602+
prev = b.SourceID
603+
}
604+
605+
// No data-stream restart should have been needed to clear a stale header-only block.
606+
// (Restarts here would be due to genuine suspicion/promotion, never a malformed data block.)
607+
malformedFromHeaders := test.GetIntMetricValue(t,
608+
e.deliveryParams.Metrics.StreamErrorsTotal.WithLabelValues("data", strconv.FormatUint(uint64(prev), 10),
609+
"malformed_block"))
610+
require.Zero(t, malformedFromHeaders, "a promoted source's queued header-only block must not be seen as malformed")
611+
}
612+
567613
type deliverOrdererTestEnvParams struct {
568614
tlsMode string
569615
ftMode string

0 commit comments

Comments
 (0)