diff --git a/x/audit/v1/keeper/audit_peer_assignment.go b/x/audit/v1/keeper/audit_peer_assignment.go index df9494a2..e2e24431 100644 --- a/x/audit/v1/keeper/audit_peer_assignment.go +++ b/x/audit/v1/keeper/audit_peer_assignment.go @@ -119,7 +119,11 @@ func computeStorageTruthTargetsForReporter(params paramsLike, activeSorted []str } active := sortedUniqueStrings(activeSorted) - targetCandidates := intersectionInOrder(sortedUniqueStrings(targetsSorted), active) + // Active supernodes are the only eligible challengers, but storage-truth targets + // must include the epoch target set captured by the anchor. That target set + // intentionally includes POSTPONED supernodes so active peers can continue + // submitting clean PASS proofs needed for storage-truth recovery. + targetCandidates := sortedUniqueStrings(targetsSorted) if len(targetCandidates) == 0 { targetCandidates = active } diff --git a/x/audit/v1/keeper/audit_peer_assignment_test.go b/x/audit/v1/keeper/audit_peer_assignment_test.go index 1611988f..45ecb3b9 100644 --- a/x/audit/v1/keeper/audit_peer_assignment_test.go +++ b/x/audit/v1/keeper/audit_peer_assignment_test.go @@ -34,6 +34,28 @@ func TestStorageTruthAssignmentUsesOneThirdCoverage(t *testing.T) { require.Len(t, assignedTargets, 2) } +func TestStorageTruthAssignmentIncludesPostponedTargets(t *testing.T) { + params := types.DefaultParams().WithDefaults() + params.StorageTruthEnforcementMode = types.StorageTruthEnforcementMode_STORAGE_TRUTH_ENFORCEMENT_MODE_FULL + params.StorageTruthChallengeTargetDivisor = 1 + + active := []string{"sn-a", "sn-b"} + targets := []string{"sn-postponed"} + seed := []byte("01234567890123456789012345678901") + + assigned := false + for _, reporter := range active { + reporterTargets, isProber, err := computeAuditPeerTargetsForReporter(¶ms, active, targets, seed, reporter) + require.NoError(t, err) + require.True(t, isProber) + if containsString(reporterTargets, "sn-postponed") { + assigned = true + } + } + + require.True(t, assigned, "active challengers must be able to target postponed supernodes for storage-truth recovery") +} + func TestStorageTruthAssignmentDisabledUsesLegacyCoverage(t *testing.T) { params := types.DefaultParams().WithDefaults() params.StorageTruthEnforcementMode = types.StorageTruthEnforcementMode_STORAGE_TRUTH_ENFORCEMENT_MODE_UNSPECIFIED