Skip to content

Commit 2c92b4b

Browse files
committed
Merge remote-tracking branch 'origin/ma/coalesce-rotation-power-updates' into eric/validate-cons-key-rotation-type
2 parents f1b3982 + 3fa2199 commit 2c92b4b

6 files changed

Lines changed: 1128 additions & 415 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
7070
* (x/staking) [#26408](https://github.com/cosmos/cosmos-sdk/pull/26408) Fix `MsgBeginRedelegate` failure when redelegating all shares from an unbonded source validator that is removed after unbonding.
7171
* (x/auth/tx) [#26422](https://github.com/cosmos/cosmos-sdk/pull/26422) Reuse the signing context from the codec's `InterfaceRegistry` when `ConfigOptions.SigningOptions` is unset so that `CustomGetSigners` registered via `NewInterfaceRegistryWithOptions` are honored by `NewTxConfig` / `NewTxConfigWithOptions`.
7272
* (blockstm) [#25893](https://github.com/cosmos/cosmos-sdk/pull/25893) Fix CancelAll cancellation by clearing blocker ESTIMATE marks before waking suspended executors.
73+
* (x/staking) [#26460](https://github.com/cosmos/cosmos-sdk/pull/26460) Coalesce key rotation power updates to not emit duplicates.
7374

7475
### Deprecated
7576

tests/integration/staking/keeper/cons_key_rotation_test.go

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"time"
66

77
cmtabcitypes "github.com/cometbft/cometbft/abci/types"
8+
cmttypes "github.com/cometbft/cometbft/types"
89
"gotest.tools/v3/assert"
910

1011
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
@@ -103,8 +104,7 @@ func TestRotateConsPubKey_MsgServerQueuesAndEndBlockerApplies(t *testing.T) {
103104
// integration fixture's EndBlocker runs with the captured initial block
104105
// height and does not advance with FinalizeBlock.
105106
applyCtx := f.sdkCtx.WithBlockHeight(writeHeight + types.ConsensusUpdateDelay)
106-
_, err = f.stakingKeeper.ProcessConsKeyRotations(applyCtx, powerReduction)
107-
assert.NilError(t, err)
107+
assert.NilError(t, f.stakingKeeper.ApplyConsKeyRotations(applyCtx))
108108

109109
// old by-cons-addr index is gone
110110
_, err = f.stakingKeeper.GetValidatorByConsAddr(f.sdkCtx, oldConsAddr)
@@ -185,7 +185,6 @@ func TestRotateConsPubKey_SecondRotationAfterPruningSucceeds(t *testing.T) {
185185
t.Parallel()
186186
f := initFixture(t)
187187
msgServer := keeper.NewMsgServerImpl(f.stakingKeeper)
188-
powerReduction := f.stakingKeeper.PowerReduction(f.sdkCtx)
189188

190189
pkA := ed25519.GenPrivKey().PubKey()
191190
pkB := ed25519.GenPrivKey().PubKey()
@@ -213,8 +212,7 @@ func TestRotateConsPubKey_SecondRotationAfterPruningSucceeds(t *testing.T) {
213212
// index moves accordingly. The integration fixture's EndBlocker keeps the
214213
// captured block height, so the drain pass is invoked here directly.
215214
applyCtx := f.sdkCtx.WithBlockHeight(writeHeight + types.ConsensusUpdateDelay)
216-
_, err = f.stakingKeeper.ProcessConsKeyRotations(applyCtx, powerReduction)
217-
assert.NilError(t, err)
215+
assert.NilError(t, f.stakingKeeper.ApplyConsKeyRotations(applyCtx))
218216

219217
// advance past maturity and let the end blocker prune
220218
unbondingTime, err := f.stakingKeeper.UnbondingTime(f.sdkCtx)
@@ -233,8 +231,7 @@ func TestRotateConsPubKey_SecondRotationAfterPruningSucceeds(t *testing.T) {
233231

234232
// drive the drain again for this second rotation
235233
applyCtx = f.sdkCtx.WithBlockHeight(writeHeight + types.ConsensusUpdateDelay)
236-
_, err = f.stakingKeeper.ProcessConsKeyRotations(applyCtx, powerReduction)
237-
assert.NilError(t, err)
234+
assert.NilError(t, f.stakingKeeper.ApplyConsKeyRotations(applyCtx))
238235

239236
stored, err := f.stakingKeeper.GetValidator(f.sdkCtx, valAddr)
240237
assert.NilError(t, err)
@@ -243,6 +240,50 @@ func TestRotateConsPubKey_SecondRotationAfterPruningSucceeds(t *testing.T) {
243240
assert.DeepEqual(t, sdk.ConsAddress(pkA.Address()).Bytes(), storedConsAddr)
244241
}
245242

243+
func TestRotateConsPubKey_PowerChangeUpdatesAcceptedByComet(t *testing.T) {
244+
t.Parallel()
245+
f := initFixture(t)
246+
msgServer := keeper.NewMsgServerImpl(f.stakingKeeper)
247+
248+
oldPk := ed25519.GenPrivKey().PubKey()
249+
newPk := ed25519.GenPrivKey().PubKey()
250+
valAddr, _ := bondConsKeyRotationValidator(t, f, oldPk)
251+
validator, err := f.stakingKeeper.GetValidator(f.sdkCtx, valAddr)
252+
assert.NilError(t, err)
253+
initialCmtVals, err := cmttypes.PB2TM.ValidatorUpdates([]cmtabcitypes.ValidatorUpdate{
254+
validator.ABCIValidatorUpdate(f.stakingKeeper.PowerReduction(f.sdkCtx)),
255+
})
256+
assert.NilError(t, err)
257+
valSet := cmttypes.NewValidatorSet(initialCmtVals)
258+
259+
_, err = msgServer.RotateConsPubKey(f.sdkCtx, &types.MsgRotateConsPubKey{
260+
ValidatorAddress: valAddr.String(),
261+
NewPubkey: newPubKeyAny(t, newPk),
262+
})
263+
assert.NilError(t, err)
264+
265+
// Force a same-height power update for the rotating validator. Staking must
266+
// coalesce this with the rotation's new-key update before returning the
267+
// batch to CometBFT.
268+
validator, err = f.stakingKeeper.GetValidator(f.sdkCtx, valAddr)
269+
assert.NilError(t, err)
270+
validator, _ = validator.AddTokensFromDel(f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, 1))
271+
keeper.TestingUpdateValidator(f.stakingKeeper, f.sdkCtx, validator, false)
272+
273+
updates, err := f.stakingKeeper.ApplyAndReturnValidatorSetUpdates(f.sdkCtx)
274+
assert.NilError(t, err)
275+
assert.Equal(t, 2, len(updates), "%v", updates)
276+
277+
cmtUpdates, err := cmttypes.PB2TM.ValidatorUpdates(updates)
278+
assert.NilError(t, err)
279+
280+
assert.NilError(t, valSet.UpdateWithChangeSet(cmtUpdates))
281+
assert.Assert(t, !valSet.HasAddress(oldPk.Address()))
282+
_, newCmtVal := valSet.GetByAddress(newPk.Address())
283+
assert.Assert(t, newCmtVal != nil)
284+
assert.Equal(t, int64(101), newCmtVal.VotingPower)
285+
}
286+
246287
// bondConsKeyRotationValidator creates and bonds a single validator under
247288
// consPk, funding the operator account with enough tokens to cover several
248289
// rotation fees plus the self delegation.

0 commit comments

Comments
 (0)