Skip to content

lastSelectedRound in /redistributionstate API is misleading for unstaked nodes #5333

@crtahlin

Description

@crtahlin

Summary

The lastSelectedRound field in the /redistributionstate API endpoint is misleading. It implies "the last round in which the node's neighborhood was selected," but it actually means "the last round in which the node was both selected AND staked." For unstaked nodes, this field is always 0 regardless of whether their neighborhood was selected.

Problem

The field is set in pkg/storageincentives/agent.go at line 410, after the IsPlaying() check at line 401:

isPlaying, err := a.contract.IsPlaying(ctx, committedDepth)
if !isPlaying {
    return false, nil  // exits before SetLastSelectedRound
}
a.state.SetLastSelectedRound(round + 1)  // only reached if staked + selected

IsPlaying() calls the smart contract's isParticipatingInUpcomingRound, which bundles neighborhood selection and stake verification into a single boolean. When a node is not staked, IsPlaying returns false and SetLastSelectedRound is never called.

This means an unstaked operator seeing lastSelectedRound: 0 cannot distinguish between:

  • "My neighborhood was never selected" (bad location)
  • "My neighborhood was selected but I'm not staked" (worth staking)

This could lead operators to incorrectly conclude their neighborhood is inactive.

Additionally

None of the four round-tracking fields (lastWonRound, lastPlayedRound, lastFrozenRound, lastSelectedRound) have any description in the OpenAPI spec (openapi/SwarmCommon.yaml). They are listed only as type: integer with no explanation of their meaning or the conditions under which they are populated.

Suggested Fix

Either:

  1. Rename lastSelectedRound to lastParticipatingRound or lastEligibleRound to accurately reflect that it requires both selection and stake.
  2. Or add a separate field (e.g., lastNeighborhoodSelectedRound) that tracks neighborhood selection independently of stake status, if the contract supports it.
  3. Add descriptions to all four fields in the OpenAPI spec explaining what each field means and when it gets populated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions