Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Breaking Changes

* (x/staking) [#25724](https://github.com/cosmos/cosmos-sdk/issues/25724) Validate `BondDenom` in `MsgUpdateParams` to prevent setting non-existent or zero-supply denoms.
* [#25778](https://github.com/cosmos/cosmos-sdk/pull/25778) Update `log` to log v2.
* [#25090](https://github.com/cosmos/cosmos-sdk/pull/25090) Moved deprecated modules to `./contrib`. These modules are still available but will no longer be actively maintained or supported in the Cosmos SDK Bug Bounty program.
* `x/group`
Expand Down
8 changes: 8 additions & 0 deletions x/staking/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,14 @@ func (k msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams)
return nil, err
}

// Validate that the bond denom exists on-chain by checking if it has supply.
// This prevents governance from setting bond_denom to a non-existent denom,
// which would place the chain in an unsafe state.
supply := k.bankKeeper.GetSupply(ctx, msg.Params.BondDenom)
if supply.IsZero() {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "bond denom %s does not exist or has zero supply", msg.Params.BondDenom)
}

// store params
if err := k.SetParams(ctx, msg.Params); err != nil {
return nil, err
Expand Down
28 changes: 28 additions & 0 deletions x/staking/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,7 @@ func (s *KeeperTestSuite) TestMsgUpdateParams() {
input *stakingtypes.MsgUpdateParams
expErr bool
expErrMsg string
setup func()
}{
{
name: "valid params",
Expand All @@ -1003,6 +1004,9 @@ func (s *KeeperTestSuite) TestMsgUpdateParams() {
Params: stakingtypes.DefaultParams(),
},
expErr: false,
setup: func() {
s.bankKeeper.EXPECT().GetSupply(gomock.Any(), stakingtypes.DefaultParams().BondDenom).Return(sdk.NewInt64Coin(stakingtypes.DefaultParams().BondDenom, 1000000))
},
},
{
name: "invalid authority",
Expand Down Expand Up @@ -1061,6 +1065,25 @@ func (s *KeeperTestSuite) TestMsgUpdateParams() {
expErr: true,
expErrMsg: "bond denom cannot be blank",
},
{
name: "invalid bond denom - zero supply",
input: &stakingtypes.MsgUpdateParams{
Authority: keeper.GetAuthority(),
Params: stakingtypes.Params{
MinCommissionRate: stakingtypes.DefaultMinCommissionRate,
UnbondingTime: stakingtypes.DefaultUnbondingTime,
MaxValidators: stakingtypes.DefaultMaxValidators,
MaxEntries: stakingtypes.DefaultMaxEntries,
HistoricalEntries: stakingtypes.DefaultHistoricalEntries,
BondDenom: "ghosttoken",
},
},
expErr: true,
expErrMsg: "does not exist or has zero supply",
setup: func() {
s.bankKeeper.EXPECT().GetSupply(gomock.Any(), "ghosttoken").Return(sdk.NewInt64Coin("ghosttoken", 0))
},
},
{
name: "max validators must be positive",
input: &stakingtypes.MsgUpdateParams{
Expand Down Expand Up @@ -1113,6 +1136,11 @@ func (s *KeeperTestSuite) TestMsgUpdateParams() {

for _, tc := range testCases {
s.T().Run(tc.name, func(t *testing.T) {
// Setup mocks if specified
if tc.setup != nil {
tc.setup()
}

_, err := msgServer.UpdateParams(ctx, tc.input)
if tc.expErr {
require.Error(err)
Expand Down
Loading