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:
- Rename
lastSelectedRound to lastParticipatingRound or lastEligibleRound to accurately reflect that it requires both selection and stake.
- Or add a separate field (e.g.,
lastNeighborhoodSelectedRound) that tracks neighborhood selection independently of stake status, if the contract supports it.
- Add descriptions to all four fields in the OpenAPI spec explaining what each field means and when it gets populated.
Summary
The
lastSelectedRoundfield in the/redistributionstateAPI 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.goat line 410, after theIsPlaying()check at line 401:IsPlaying()calls the smart contract'sisParticipatingInUpcomingRound, which bundles neighborhood selection and stake verification into a single boolean. When a node is not staked,IsPlayingreturnsfalseandSetLastSelectedRoundis never called.This means an unstaked operator seeing
lastSelectedRound: 0cannot distinguish between: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 astype: integerwith no explanation of their meaning or the conditions under which they are populated.Suggested Fix
Either:
lastSelectedRoundtolastParticipatingRoundorlastEligibleRoundto accurately reflect that it requires both selection and stake.lastNeighborhoodSelectedRound) that tracks neighborhood selection independently of stake status, if the contract supports it.