fix: poa unbond all validator delegations on removal#141
Conversation
📝 WalkthroughWalkthroughThe POA keeper's ExecuteRemoveValidator now fetches all delegations for a validator, decodes delegator Bech32 addresses, and unbonds each delegation individually. A StakingKeeper interface method GetValidatorDelegations was added and mocks/tests updated to exercise delegation-driven unbonding. ChangesDelegation-Based Unbonding Refactor
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.1)Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
6143a41 to
7f71d01
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
x/poa/keeper/keeper.go (1)
257-264: 💤 Low valueOptional: consolidate the parallel
delegations/delegatorAddrsslices.Index-aligned parallel slices are easy to break in future refactors. A small local struct (or storing the pair) makes the relationship explicit without changing behavior.
♻️ Proposed refactor
- delegatorAddrs := make([]sdk.AccAddress, 0, len(delegations)) - for _, del := range delegations { - delAddr, err := sdk.AccAddressFromBech32(del.DelegatorAddress) - if err != nil { - return errors.Wrapf(err, "invalid delegator address %q for validator %q", del.DelegatorAddress, validatorAddress) - } - delegatorAddrs = append(delegatorAddrs, delAddr) - } + type pendingUnbond struct { + delAddr sdk.AccAddress + shares math.LegacyDec + bech32 string + } + pending := make([]pendingUnbond, 0, len(delegations)) + for _, del := range delegations { + delAddr, err := sdk.AccAddressFromBech32(del.DelegatorAddress) + if err != nil { + return errors.Wrapf(err, "invalid delegator address %q for validator %q", del.DelegatorAddress, validatorAddress) + } + pending = append(pending, pendingUnbond{delAddr: delAddr, shares: del.Shares, bech32: del.DelegatorAddress}) + } @@ - for i, del := range delegations { - if _, err := k.sk.Unbond(ctx, delegatorAddrs[i], valAddress, del.Shares); err != nil { - return errors.Wrapf(err, "failed to unbond delegation from %q to validator %q", del.DelegatorAddress, validatorAddress) + for _, p := range pending { + if _, err := k.sk.Unbond(ctx, p.delAddr, valAddress, p.shares); err != nil { + return errors.Wrapf(err, "failed to unbond delegation from %q to validator %q", p.bech32, validatorAddress) } }Also applies to: 288-295
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@x/poa/keeper/keeper.go` around lines 257 - 264, The code builds index-aligned parallel slices delegations and delegatorAddrs which is error-prone; refactor to a single local struct slice (e.g., type delegatorPair struct { delegation stakingtypes.Delegation; addr sdk.AccAddress }) and populate that in the loop that currently calls sdk.AccAddressFromBech32 for each del and appends to delegatorAddrs (refer to variables delegations, delegatorAddrs, sdk.AccAddressFromBech32 and validatorAddress); update subsequent usage sites (the block around lines 288-295 mentioned in the comment) to iterate the new slice of pairs instead of relying on two parallel slices, preserving the existing error handling and return behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@x/poa/keeper/keeper.go`:
- Around line 257-264: The code builds index-aligned parallel slices delegations
and delegatorAddrs which is error-prone; refactor to a single local struct slice
(e.g., type delegatorPair struct { delegation stakingtypes.Delegation; addr
sdk.AccAddress }) and populate that in the loop that currently calls
sdk.AccAddressFromBech32 for each del and appends to delegatorAddrs (refer to
variables delegations, delegatorAddrs, sdk.AccAddressFromBech32 and
validatorAddress); update subsequent usage sites (the block around lines 288-295
mentioned in the comment) to iterate the new slice of pairs instead of relying
on two parallel slices, preserving the existing error handling and return
behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 54f19a55-80f7-4dd6-92e9-f9d36fd0cac3
📒 Files selected for processing (4)
x/poa/keeper/keeper.gox/poa/keeper/keeper_test.gox/poa/testutil/expected_keepers_mock.gox/poa/types/expected_keepers.go
🚧 Files skipped from review as they are similar to previous changes (1)
- x/poa/testutil/expected_keepers_mock.go
fix: poa unbond all validator delegations on removal
Motivation 💡
Changes 🛠
GetValidatorDelegationsto the expected staking keeper interface and generated mock.ExecuteRemoveValidatorunit tests for self-delegation, foreign delegators, invalid delegator addresses, and unbond failures.Summary by CodeRabbit
Bug Fixes
Tests