From 7f71d0195d08907754ae30a8b38b392fda2fa3d1 Mon Sep 17 00:00:00 2001 From: Kevin Pita Date: Tue, 5 May 2026 08:56:34 +0200 Subject: [PATCH] fix: poa unbond all validator delegations on removal --- x/poa/keeper/keeper.go | 25 +- x/poa/keeper/keeper_test.go | 309 ++++++++++++++++++++++-- x/poa/testutil/expected_keepers_mock.go | 15 ++ x/poa/types/expected_keepers.go | 1 + 4 files changed, 330 insertions(+), 20 deletions(-) diff --git a/x/poa/keeper/keeper.go b/x/poa/keeper/keeper.go index 5a6af7bd..0774c8d4 100644 --- a/x/poa/keeper/keeper.go +++ b/x/poa/keeper/keeper.go @@ -249,6 +249,20 @@ func (k Keeper) ExecuteRemoveValidator(ctx sdk.Context, validatorAddress string) } } + // Fetch and validate delegations before mutating state. + delegations, err := k.sk.GetValidatorDelegations(ctx, valAddress) + if err != nil { + return err + } + 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) + } + changedVal, err := k.sk.RemoveValidatorTokens(ctx, validator, validator.Tokens) if err != nil { return err @@ -271,10 +285,13 @@ func (k Keeper) ExecuteRemoveValidator(ctx sdk.Context, validatorAddress string) return types.ErrInvalidValidatorStatus } - // Unbond self-delegation so the validator is removed after being unbonded - _, err = k.sk.Unbond(ctx, sdk.AccAddress(valAddress), valAddress, changedVal.DelegatorShares) - if err != nil { - return err + // Burn the validator tokens first to preserve POA removal semantics: stake is + // destroyed, not returned to delegators. Unbond is still used afterwards so + // staking removes each delegation's shares through its normal hooks/indexes. + 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) + } } ctx.EventManager().EmitEvent( diff --git a/x/poa/keeper/keeper_test.go b/x/poa/keeper/keeper_test.go index 90103974..47331199 100644 --- a/x/poa/keeper/keeper_test.go +++ b/x/poa/keeper/keeper_test.go @@ -26,6 +26,7 @@ func poaKeeperTestSetup(t *testing.T) (*Keeper, sdk.Context) { }, nil).AnyTimes() stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(stakingtypes.Validator{Tokens: math.NewInt(0)}, nil).AnyTimes() stakingKeeper.EXPECT().GetAllDelegatorDelegations(ctx, gomock.Any()).Return([]stakingtypes.Delegation{}, nil).AnyTimes() + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return([]stakingtypes.Delegation{}, nil).AnyTimes() stakingKeeper.EXPECT().GetUnbondingDelegationsFromValidator(ctx, gomock.Any()).Return([]stakingtypes.UnbondingDelegation{}, nil).AnyTimes() stakingKeeper.EXPECT().SlashUnbondingDelegation(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(math.ZeroInt(), nil).AnyTimes() stakingKeeper.EXPECT().RemoveDelegation(ctx, gomock.Any()).Return(nil).AnyTimes() @@ -425,6 +426,15 @@ func TestKeeper_ExecuteAddValidator(t *testing.T) { } } +func mustAccAddress(t testing.TB, address string) sdk.AccAddress { + t.Helper() + + accAddr, err := sdk.AccAddressFromBech32(address) + require.NoError(t, err) + + return accAddr +} + func TestKeeper_ExecuteRemoveValidator(t *testing.T) { ctrl := gomock.NewController(t) @@ -525,12 +535,41 @@ func TestKeeper_ExecuteRemoveValidator(t *testing.T) { hooks.EXPECT().BeforeValidatorSlashed(ctx, gomock.Any(), gomock.Any()).Return(errors.New("staking keeper hook error")) stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + []stakingtypes.Delegation{}, nil, + ) + stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, gomock.Any(), gomock.Any()).Return( stakingtypes.Validator{}, errors.New("staking keeper remove validator tokens error"), ) }, bankMocks: func(_ sdk.Context, _ *testutil.MockBankKeeper) {}, }, + { + name: "should fail - staking keeper returns error on GetValidatorDelegations", + validatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + expectedError: errors.New("staking keeper get validator delegations error"), + stakingMocks: func(ctx sdk.Context, stakingKeeper *testutil.MockStakingKeeper) { + stakingKeeper.EXPECT().GetParams(ctx).Return(stakingtypes.Params{ + BondDenom: "BND", + }, nil) + stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(stakingtypes.Validator{ + Tokens: math.NewInt(0), + }, nil) + stakingKeeper.EXPECT().GetUnbondingDelegationsFromValidator(ctx, gomock.Any()).Return( + []stakingtypes.UnbondingDelegation{}, nil, + ) + + hooks := testutil.NewMockStakingHooks(ctrl) + hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) + stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() + + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + nil, errors.New("staking keeper get validator delegations error"), + ) + }, + bankMocks: func(_ sdk.Context, _ *testutil.MockBankKeeper) {}, + }, //nolint:dupl { name: "should fail - bank keeper returns error on call BurnCoins for status bonded", @@ -538,28 +577,46 @@ func TestKeeper_ExecuteRemoveValidator(t *testing.T) { expectedError: errors.New("bank keeper burn coins error"), //nolint:dupl stakingMocks: func(ctx sdk.Context, stakingKeeper *testutil.MockStakingKeeper) { + validatorTokens := math.NewInt(10) + validator := stakingtypes.Validator{ + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Tokens: validatorTokens, + DelegatorShares: math.LegacyNewDec(10), + Status: stakingtypes.Bonded, + } + stakingKeeper.EXPECT().GetParams(ctx).Return(stakingtypes.Params{ BondDenom: "BND", }, nil) - stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(stakingtypes.Validator{ - Tokens: math.NewInt(0), - }, nil) + stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(validator, nil) stakingKeeper.EXPECT().GetUnbondingDelegationsFromValidator(ctx, gomock.Any()).Return( []stakingtypes.UnbondingDelegation{}, nil, ) hooks := testutil.NewMockStakingHooks(ctrl) hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) + hooks.EXPECT().BeforeValidatorSlashed(ctx, gomock.Any(), math.LegacyOneDec()).Return(nil) stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() - stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, gomock.Any(), gomock.Any()).Return( + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + []stakingtypes.Delegation{}, nil, + ) + + stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, validator, validatorTokens).Return( stakingtypes.Validator{ - Status: stakingtypes.Bonded, + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + DelegatorShares: validator.DelegatorShares, + Status: stakingtypes.Bonded, }, nil, ) }, bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { - bankKeeper.EXPECT().BurnCoins(ctx, gomock.Any(), gomock.Any()).Return(errors.New("bank keeper burn coins error")) + validatorTokens := math.NewInt(10) + bankKeeper.EXPECT().BurnCoins( + ctx, + stakingtypes.BondedPoolName, + sdk.NewCoins(sdk.NewCoin("BND", validatorTokens)), + ).Return(errors.New("bank keeper burn coins error")) }, }, //nolint:dupl @@ -569,35 +626,52 @@ func TestKeeper_ExecuteRemoveValidator(t *testing.T) { expectedError: errors.New("bank keeper burn coins error"), //nolint:dupl stakingMocks: func(ctx sdk.Context, stakingKeeper *testutil.MockStakingKeeper) { + validatorTokens := math.NewInt(10) + validator := stakingtypes.Validator{ + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Tokens: validatorTokens, + DelegatorShares: math.LegacyNewDec(10), + Status: stakingtypes.Unbonding, + } + stakingKeeper.EXPECT().GetParams(ctx).Return(stakingtypes.Params{ BondDenom: "BND", }, nil) - stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(stakingtypes.Validator{ - Tokens: math.NewInt(0), - }, nil) + stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(validator, nil) stakingKeeper.EXPECT().GetUnbondingDelegationsFromValidator(ctx, gomock.Any()).Return( []stakingtypes.UnbondingDelegation{}, nil, ) hooks := testutil.NewMockStakingHooks(ctrl) hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) + hooks.EXPECT().BeforeValidatorSlashed(ctx, gomock.Any(), math.LegacyOneDec()).Return(nil) stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() - stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, gomock.Any(), gomock.Any()).Return( + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + []stakingtypes.Delegation{}, nil, + ) + + stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, validator, validatorTokens).Return( stakingtypes.Validator{ - Status: stakingtypes.Unbonding, + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + DelegatorShares: validator.DelegatorShares, + Status: stakingtypes.Unbonding, }, nil, ) }, bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { - bankKeeper.EXPECT().BurnCoins(ctx, gomock.Any(), gomock.Any()).Return(errors.New("bank keeper burn coins error")) + validatorTokens := math.NewInt(10) + bankKeeper.EXPECT().BurnCoins( + ctx, + stakingtypes.NotBondedPoolName, + sdk.NewCoins(sdk.NewCoin("BND", validatorTokens)), + ).Return(errors.New("bank keeper burn coins error")) }, }, { name: "should fail - bank keeper returns error for invalid validator status", validatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", expectedError: types.ErrInvalidValidatorStatus, - //nolint:dupl stakingMocks: func(ctx sdk.Context, stakingKeeper *testutil.MockStakingKeeper) { stakingKeeper.EXPECT().GetParams(ctx).Return(stakingtypes.Params{ BondDenom: "BND", @@ -613,6 +687,10 @@ func TestKeeper_ExecuteRemoveValidator(t *testing.T) { hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + []stakingtypes.Delegation{}, nil, + ) + stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, gomock.Any(), gomock.Any()).Return( stakingtypes.Validator{ Status: stakingtypes.Unspecified, @@ -640,20 +718,219 @@ func TestKeeper_ExecuteRemoveValidator(t *testing.T) { hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + []stakingtypes.Delegation{{ + DelegatorAddress: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + ValidatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Shares: math.LegacyOneDec(), + }}, nil, + ) + stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, gomock.Any(), gomock.Any()).Return( stakingtypes.Validator{ Status: stakingtypes.Bonded, }, nil, ) - stakingKeeper.EXPECT().Unbond(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return( - math.NewInt(0), errors.New("staking keeper unbond error"), - ) + stakingKeeper.EXPECT().Unbond( + ctx, + mustAccAddress(t, "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp"), + gomock.Any(), + math.LegacyOneDec(), + ).Return(math.NewInt(0), errors.New("staking keeper unbond error")) }, bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { bankKeeper.EXPECT().BurnCoins(ctx, gomock.Any(), gomock.Any()).Return(nil) }, }, + { + name: "should fail - invalid delegator bech32 in delegation list", + validatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + expectedError: errors.New("decoding bech32 failed"), + stakingMocks: func(ctx sdk.Context, stakingKeeper *testutil.MockStakingKeeper) { + stakingKeeper.EXPECT().GetParams(ctx).Return(stakingtypes.Params{ + BondDenom: "BND", + }, nil) + stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(stakingtypes.Validator{ + Tokens: math.NewInt(0), + }, nil) + stakingKeeper.EXPECT().GetUnbondingDelegationsFromValidator(ctx, gomock.Any()).Return( + []stakingtypes.UnbondingDelegation{}, nil, + ) + + hooks := testutil.NewMockStakingHooks(ctrl) + hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) + stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() + + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + []stakingtypes.Delegation{{ + DelegatorAddress: "not-a-valid-bech32", + ValidatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Shares: math.LegacyOneDec(), + }}, nil, + ) + }, + bankMocks: func(_ sdk.Context, _ *testutil.MockBankKeeper) {}, + }, + { + name: "should succeed - no delegations skips unbond", + validatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + expectedError: nil, + stakingMocks: func(ctx sdk.Context, stakingKeeper *testutil.MockStakingKeeper) { + validatorTokens := math.ZeroInt() + validator := stakingtypes.Validator{ + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Tokens: validatorTokens, + } + + stakingKeeper.EXPECT().GetParams(ctx).Return(stakingtypes.Params{ + BondDenom: "BND", + }, nil) + stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(validator, nil) + stakingKeeper.EXPECT().GetUnbondingDelegationsFromValidator(ctx, gomock.Any()).Return( + []stakingtypes.UnbondingDelegation{}, nil, + ) + + hooks := testutil.NewMockStakingHooks(ctrl) + hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) + stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() + + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return([]stakingtypes.Delegation{}, nil) + + stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, validator, validatorTokens).Return( + stakingtypes.Validator{ + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Status: stakingtypes.Bonded, + }, nil, + ) + }, + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + bankKeeper.EXPECT().BurnCoins( + ctx, + stakingtypes.BondedPoolName, + sdk.NewCoins(sdk.NewCoin("BND", math.ZeroInt())), + ).Return(nil) + }, + }, + { + name: "should succeed - burns tokens and unbonds only self delegation", + validatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + expectedError: nil, + stakingMocks: func(ctx sdk.Context, stakingKeeper *testutil.MockStakingKeeper) { + selfDelegatorAddr := mustAccAddress(t, "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp") + validatorTokens := math.NewInt(1) + validator := stakingtypes.Validator{ + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Tokens: validatorTokens, + DelegatorShares: math.LegacyOneDec(), + Status: stakingtypes.Bonded, + } + + stakingKeeper.EXPECT().GetParams(ctx).Return(stakingtypes.Params{ + BondDenom: "BND", + }, nil) + stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(validator, nil) + stakingKeeper.EXPECT().GetUnbondingDelegationsFromValidator(ctx, gomock.Any()).Return( + []stakingtypes.UnbondingDelegation{}, nil, + ) + + hooks := testutil.NewMockStakingHooks(ctrl) + hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) + hooks.EXPECT().BeforeValidatorSlashed(ctx, gomock.Any(), math.LegacyOneDec()).Return(nil) + stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() + + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + []stakingtypes.Delegation{ + { + DelegatorAddress: selfDelegatorAddr.String(), + ValidatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Shares: math.LegacyOneDec(), + }, + }, nil, + ) + + stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, validator, validatorTokens).Return( + stakingtypes.Validator{ + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + DelegatorShares: validator.DelegatorShares, + Status: stakingtypes.Bonded, + }, nil, + ) + + stakingKeeper.EXPECT().Unbond(ctx, selfDelegatorAddr, gomock.Any(), math.LegacyOneDec()).Return(math.NewInt(0), nil) + }, + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + validatorTokens := math.NewInt(1) + bankKeeper.EXPECT().BurnCoins( + ctx, + stakingtypes.BondedPoolName, + sdk.NewCoins(sdk.NewCoin("BND", validatorTokens)), + ).Return(nil) + }, + }, + { + name: "should succeed - burns tokens and unbonds self plus foreign delegators", + validatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + expectedError: nil, + stakingMocks: func(ctx sdk.Context, stakingKeeper *testutil.MockStakingKeeper) { + selfDelegatorAddr := mustAccAddress(t, "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp") + foreignDelegatorAddr := mustAccAddress(t, "ethm1wunfhl05vc8r8xxnnp8gt62wa54r6y52pg03zq") + validatorTokens := math.NewInt(3) + validator := stakingtypes.Validator{ + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Tokens: validatorTokens, + DelegatorShares: math.LegacyNewDec(3), + Status: stakingtypes.Bonded, + } + + stakingKeeper.EXPECT().GetParams(ctx).Return(stakingtypes.Params{ + BondDenom: "BND", + }, nil) + stakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return(validator, nil) + stakingKeeper.EXPECT().GetUnbondingDelegationsFromValidator(ctx, gomock.Any()).Return( + []stakingtypes.UnbondingDelegation{}, nil, + ) + + hooks := testutil.NewMockStakingHooks(ctrl) + hooks.EXPECT().BeforeValidatorModified(ctx, gomock.Any()).Return(nil) + hooks.EXPECT().BeforeValidatorSlashed(ctx, gomock.Any(), math.LegacyOneDec()).Return(nil) + stakingKeeper.EXPECT().Hooks().Return(hooks).AnyTimes() + + stakingKeeper.EXPECT().GetValidatorDelegations(ctx, gomock.Any()).Return( + []stakingtypes.Delegation{ + { + DelegatorAddress: selfDelegatorAddr.String(), + ValidatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Shares: math.LegacyOneDec(), + }, + { + DelegatorAddress: foreignDelegatorAddr.String(), + ValidatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + Shares: math.LegacyNewDec(2), + }, + }, nil, + ) + + stakingKeeper.EXPECT().RemoveValidatorTokens(ctx, validator, validatorTokens).Return( + stakingtypes.Validator{ + OperatorAddress: "ethmvaloper1a0pd5cyew47pvgf7rd7axxy3humv9ev0urudmu", + DelegatorShares: validator.DelegatorShares, + Status: stakingtypes.Bonded, + }, nil, + ) + + stakingKeeper.EXPECT().Unbond(ctx, selfDelegatorAddr, gomock.Any(), math.LegacyOneDec()).Return(math.NewInt(0), nil) + stakingKeeper.EXPECT().Unbond(ctx, foreignDelegatorAddr, gomock.Any(), math.LegacyNewDec(2)).Return(math.NewInt(0), nil) + }, + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + validatorTokens := math.NewInt(3) + bankKeeper.EXPECT().BurnCoins( + ctx, + stakingtypes.BondedPoolName, + sdk.NewCoins(sdk.NewCoin("BND", validatorTokens)), + ).Return(nil) + }, + }, } for _, tc := range tt { diff --git a/x/poa/testutil/expected_keepers_mock.go b/x/poa/testutil/expected_keepers_mock.go index 203a15cd..21f56a41 100644 --- a/x/poa/testutil/expected_keepers_mock.go +++ b/x/poa/testutil/expected_keepers_mock.go @@ -314,6 +314,21 @@ func (mr *MockStakingKeeperMockRecorder) GetValidator(ctx, addr interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidator", reflect.TypeOf((*MockStakingKeeper)(nil).GetValidator), ctx, addr) } +// GetValidatorDelegations mocks base method. +func (m *MockStakingKeeper) GetValidatorDelegations(ctx context.Context, valAddr types.ValAddress) ([]types1.Delegation, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetValidatorDelegations", ctx, valAddr) + ret0, _ := ret[0].([]types1.Delegation) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetValidatorDelegations indicates an expected call of GetValidatorDelegations. +func (mr *MockStakingKeeperMockRecorder) GetValidatorDelegations(ctx, valAddr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatorDelegations", reflect.TypeOf((*MockStakingKeeper)(nil).GetValidatorDelegations), ctx, valAddr) +} + // GetValidators mocks base method. func (m *MockStakingKeeper) GetValidators(ctx context.Context, maxRetrieve uint32) ([]types1.Validator, error) { m.ctrl.T.Helper() diff --git a/x/poa/types/expected_keepers.go b/x/poa/types/expected_keepers.go index 6578a32a..e95d24a5 100644 --- a/x/poa/types/expected_keepers.go +++ b/x/poa/types/expected_keepers.go @@ -36,6 +36,7 @@ type StakingKeeper interface { GetAllValidators(ctx context.Context) (validators []stakingtypes.Validator, err error) GetAllDelegations(ctx context.Context) (delegations []stakingtypes.Delegation, err error) GetAllDelegatorDelegations(ctx context.Context, delegator sdk.AccAddress) ([]stakingtypes.Delegation, error) + GetValidatorDelegations(ctx context.Context, valAddr sdk.ValAddress) ([]stakingtypes.Delegation, error) GetUnbondingDelegationsFromValidator(ctx context.Context, validator sdk.ValAddress) ([]stakingtypes.UnbondingDelegation, error) SlashUnbondingDelegation(ctx context.Context, ubd stakingtypes.UnbondingDelegation, infractionHeight int64, slashFactor math.LegacyDec) (totalSlashAmount math.Int, err error) RemoveDelegation(ctx context.Context, delegation stakingtypes.Delegation) error