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