Skip to content

fix(subnet): add overflow guards for all uint32 fields in SubnetHostEpochStats#1014

Open
Mayveskii wants to merge 1 commit intogonka-ai:mainfrom
Mayveskii:fix/subnet-host-stats-overflow
Open

fix(subnet): add overflow guards for all uint32 fields in SubnetHostEpochStats#1014
Mayveskii wants to merge 1 commit intogonka-ai:mainfrom
Mayveskii:fix/subnet-host-stats-overflow

Conversation

@Mayveskii
Copy link
Copy Markdown

Problem

AggregateSubnetHostStats guards Cost (uint64) against overflow (existing guard from PR #544) but leaves four uint32 fields unprotected:

  • Missed — no guard
  • Invalid — no guard
  • RequiredValidations — no guard
  • CompletedValidations — no guard

IncrementSubnetHostEscrowCount increments EscrowCount (uint32) with no bound check.

uint32 wraps at 4,294,967,295. If RequiredValidations wraps to 0 while CompletedValidations remains non-zero, downstream completion-rate logic produces division-by-zero or inflated ratios. Severity escalates to HIGH when issues #976/#977 integrate these stats into the punishment/reward pipeline.

Closes #979

Fix

Add math.MaxUint32 subtraction guards for all five uint32 accumulation sites, following the established pattern from PR #544:

if existing.Missed > math.MaxUint32-slotStats.Missed {
    return fmt.Errorf("missed overflow: existing=%d add=%d", existing.Missed, slotStats.Missed)
}
existing.Missed += slotStats.Missed

For EscrowCount increment:

if existing.EscrowCount == math.MaxUint32 {
    return fmt.Errorf("escrow count overflow for participant %s epoch %d", ...)
}
existing.EscrowCount++

Impact

Before: uint32 counters silently wrap to zero on overflow — corrupted stats stored on-chain with no error signal.

After: any accumulation that would overflow returns an error, halting stats aggregation for that slot. No impact on current punishment pipeline (stats not yet wired to INACTIVE/INVALID logic). Must be merged before #976/#977.

If AggregateSubnetHostStats returns an error from within SettleSubnetEscrow, Cosmos SDK rolls back the full tx via CacheContext — no partial bank payments are committed.

Tests added: subnet_host_stats_test.go — 7 tests covering all 5 fields (Missed, Invalid, RequiredValidations, CompletedValidations, EscrowCount overflow) + happy path.

Run with: CGO_CFLAGS='-D__BLST_PORTABLE__' go test ./x/inference/keeper/... -run TestAggregateSubnetHostStats

…Stats

Add math.MaxUint32 guards for Missed, Invalid, RequiredValidations,
CompletedValidations in AggregateSubnetHostStats and EscrowCount guard
in IncrementSubnetHostEscrowCount, following the pattern from PR gonka-ai#544.

Without guards, any of these uint32 fields can silently wrap to zero.
RequiredValidations wrapping to zero while CompletedValidations is non-zero
produces division-by-zero or infinite completion rate in downstream
reward/punishment logic (critical before merging gonka-ai#976/gonka-ai#977).

Closes gonka-ai#979
@0xgonka 0xgonka self-requested a review April 10, 2026 16:37
Copy link
Copy Markdown

@Doog-bot534 Doog-bot534 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: fix(subnet): add overflow guards for all uint32 fields in SubnetHostEpochStats

Approve

Correct and well-scoped. Adds pre-addition overflow checks for Missed, Invalid, RequiredValidations, CompletedValidations (uint32), and EscrowCount (uint32 increment). The pattern existing.X > math.MaxUint32 - slotStats.X is canonical safe overflow check.

Strengths

  • Comprehensive: covers all five uint32 fields plus the existing uint64 Cost guard
  • Error messages for new fields include diagnostic values (existing=%d add=%d)
  • Tests cover each overflow boundary and happy path

Suggestions

  1. The original Cost overflow message doesn't include diagnostic values — consider updating for consistency.
  2. Add a test verifying two large-but-not-overflowing values succeed (e.g., MaxUint32/2 + MaxUint32/2).
  3. Confirm the caller of AggregateSubnetHostStats handles error return gracefully (log and skip, not chain halt).

Payout address: gonka10zaal553duxp05nvfpqtsqrm2g0j6j34r8nan7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

devshards escrow: fund loss on unsettled pruning + missing overflow guards in host stats aggregation

3 participants