Skip to content

Commit f2e6295

Browse files
Merge commit from fork
* fix * changelog and release notes
1 parent 7b9d2ff commit f2e6295

File tree

4 files changed

+162
-10
lines changed

4 files changed

+162
-10
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ Ref: https://keepachangelog.com/en/1.0.0/
3636

3737
# Changelog
3838

39-
## [Unreleased]
39+
## [v0.50.14](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.14) - 2025-07-08
40+
41+
### Bug Fixes
42+
43+
* [GHSA-p22h-3m2v-cmgh](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-p22h-3m2v-cmgh) Fix x/distribution can halt when historical rewards overflow.
4044

4145

4246
## [v0.50.13](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.13) - 2025-03-12

RELEASE_NOTES.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
# Cosmos SDK v0.50.12 Release Notes
2-
3-
💬 [**Release Discussion**](https://github.com/orgs/cosmos/discussions/58)
1+
# Cosmos SDK v0.50.14 Release Notes
42

53
## 🚀 Highlights
64

7-
This patch release fixes [GHSA-x5vx-95h7-rv4p](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-x5vx-95h7-rv4p).
8-
It resolves a `x/group` module issue that can halt chain when handling a malicious proposal.
9-
Only users of the `x/group` module are affected by this issue.
5+
This patch release fixes [GHSA-p22h-3m2v-cmgh](https://github.com/cosmos/cosmos-sdk/security/advisories/GHSA-p22h-3m2v-cmgh).
6+
It resolves a `x/distribution` module issue that can halt chains when the historical rewards pool overflows.
7+
Chains using the `x/distribution` module are affected by this issue.
8+
9+
We recommended upgrading to this patch release as soon as possible.
1010

11-
We recommended to upgrade to this patch release as soon as possible.
12-
When upgrading from <= v0.50.11, please use a chain upgrade to ensure that 2/3 of the validator power upgrade to v0.50.12.
11+
This patch is state-breaking; chains must perform a coordinated upgrade. This patch cannot be applied in a rolling upgrade.
1312

1413
## 📝 Changelog
1514

16-
Check out the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.50.12/CHANGELOG.md) for an exhaustive list of changes, or [compare changes](https://github.com/cosmos/cosmos-sdk/compare/v0.50.11...v0.50.12) from the last release.
15+
Check out the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.50.14/CHANGELOG.md) for an exhaustive list of changes or [compare changes](https://github.com/cosmos/cosmos-sdk/compare/v0.50.13...v0.50.14) from the last release.

tests/integration/distribution/keeper/msg_server_test.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package keeper_test
22

33
import (
4+
"encoding/hex"
45
"fmt"
56
"testing"
67

78
cmtabcitypes "github.com/cometbft/cometbft/abci/types"
89
"github.com/cometbft/cometbft/proto/tendermint/types"
10+
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
11+
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
12+
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
913
"github.com/stretchr/testify/require"
1014
"gotest.tools/v3/assert"
1115

@@ -72,6 +76,7 @@ func initFixture(t testing.TB) *fixture {
7276

7377
maccPerms := map[string][]string{
7478
distrtypes.ModuleName: {authtypes.Minter},
79+
minttypes.ModuleName: {authtypes.Minter},
7580
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
7681
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
7782
}
@@ -132,10 +137,18 @@ func initFixture(t testing.TB) *fixture {
132137
})
133138

134139
sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context())
140+
require.NoError(t, stakingKeeper.SetParams(sdkCtx, stakingtypes.DefaultParams()))
141+
142+
stakingKeeper.SetHooks(
143+
stakingtypes.NewMultiStakingHooks(
144+
distrKeeper.Hooks(), // Needed for reward distribution on staking events
145+
),
146+
)
135147

136148
// Register MsgServer and QueryServer
137149
distrtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), distrkeeper.NewMsgServerImpl(distrKeeper))
138150
distrtypes.RegisterQueryServer(integrationApp.QueryHelper(), distrkeeper.NewQuerier(distrKeeper))
151+
stakingtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), stakingkeeper.NewMsgServerImpl(stakingKeeper))
139152

140153
return &fixture{
141154
app: integrationApp,
@@ -982,3 +995,108 @@ func TestMsgDepositValidatorRewardsPool(t *testing.T) {
982995
})
983996
}
984997
}
998+
999+
func TestCannotDepositIfRewardPoolFull(t *testing.T) {
1000+
f := initFixture(t)
1001+
err := f.distrKeeper.FeePool.Set(f.sdkCtx, distrtypes.FeePool{
1002+
CommunityPool: sdk.NewDecCoins(sdk.DecCoin{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(10000)}),
1003+
})
1004+
assert.NilError(t, err)
1005+
assert.NilError(t, f.distrKeeper.Params.Set(f.sdkCtx, distrtypes.DefaultParams()))
1006+
_, err = f.distrKeeper.FeePool.Get(f.sdkCtx)
1007+
assert.NilError(t, err)
1008+
1009+
ctx := f.sdkCtx.WithIsCheckTx(false).WithBlockHeight(1)
1010+
populateValidators(t, f)
1011+
1012+
valPubKey := newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB53")
1013+
operatorAddr := sdk.ValAddress(valPubKey.Address())
1014+
1015+
tstaking := stakingtestutil.NewHelper(t, ctx, f.stakingKeeper)
1016+
1017+
assert.NilError(t, f.bankKeeper.MintCoins(f.sdkCtx, minttypes.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))))
1018+
assert.NilError(t, f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, minttypes.ModuleName, sdk.AccAddress(operatorAddr), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))))
1019+
1020+
tstaking.Commission = stakingtypes.NewCommissionRates(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec())
1021+
selfDelegation := math.OneInt()
1022+
tstaking.CreateValidator(operatorAddr, valPubKey, selfDelegation, true)
1023+
1024+
_, err = f.stakingKeeper.EndBlocker(f.sdkCtx)
1025+
assert.NilError(t, err)
1026+
1027+
testDenom := "utesttest"
1028+
maxSupply, ok := math.NewIntFromString("115792089237316195423570985008687907853269984665640564039457584007913129639934")
1029+
assert.Assert(t, ok)
1030+
maxCoins := sdk.NewCoins(sdk.NewCoin(testDenom, maxSupply))
1031+
assert.NilError(t, f.bankKeeper.MintCoins(f.sdkCtx, minttypes.ModuleName, maxCoins))
1032+
assert.NilError(t, f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, minttypes.ModuleName, sdk.AccAddress(operatorAddr), maxCoins))
1033+
1034+
fundValMsg := &distrtypes.MsgDepositValidatorRewardsPool{
1035+
Depositor: sdk.AccAddress(operatorAddr).String(),
1036+
ValidatorAddress: operatorAddr.String(),
1037+
Amount: maxCoins,
1038+
}
1039+
1040+
// fund the rewards pool. this will set the current rewards.
1041+
_, err = f.app.RunMsg(
1042+
fundValMsg,
1043+
integration.WithAutomaticFinalizeBlock(),
1044+
integration.WithAutomaticCommit(),
1045+
)
1046+
assert.NilError(t, err)
1047+
1048+
// now we delegate to increment the validator period, setting the current rewards to the previous.
1049+
power := int64(1)
1050+
delegationAmount := sdk.TokensFromConsensusPower(power, sdk.DefaultPowerReduction)
1051+
delMsg := stakingtypes.NewMsgDelegate(sdk.AccAddress(operatorAddr).String(), operatorAddr.String(), sdk.NewCoin(sdk.DefaultBondDenom, delegationAmount))
1052+
_, err = f.app.RunMsg(
1053+
delMsg,
1054+
integration.WithAutomaticFinalizeBlock(),
1055+
integration.WithAutomaticCommit(),
1056+
)
1057+
assert.NilError(t, err)
1058+
1059+
// this should fail since this amount cannot be added to the previous amount without overflowing.
1060+
_, err = f.app.RunMsg(
1061+
fundValMsg,
1062+
integration.WithAutomaticFinalizeBlock(),
1063+
integration.WithAutomaticCommit(),
1064+
)
1065+
assert.ErrorContains(t, err, "unable to deposit coins")
1066+
}
1067+
1068+
var (
1069+
pubkeys = []cryptotypes.PubKey{
1070+
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"),
1071+
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"),
1072+
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"),
1073+
}
1074+
1075+
valAddresses = []sdk.ValAddress{
1076+
sdk.ValAddress(pubkeys[0].Address()),
1077+
sdk.ValAddress(pubkeys[1].Address()),
1078+
sdk.ValAddress(pubkeys[2].Address()),
1079+
}
1080+
1081+
initAmt = sdk.TokensFromConsensusPower(1000000, sdk.DefaultPowerReduction)
1082+
initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))
1083+
)
1084+
1085+
func populateValidators(t assert.TestingT, f *fixture) {
1086+
totalSupplyAmt := initAmt.MulRaw(int64(len(valAddresses)))
1087+
totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, totalSupplyAmt))
1088+
assert.NilError(t, f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, totalSupply))
1089+
1090+
for _, addr := range valAddresses {
1091+
assert.NilError(t, f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, distrtypes.ModuleName, (sdk.AccAddress)(addr), initCoins))
1092+
}
1093+
}
1094+
1095+
func newPubKey(pk string) (res cryptotypes.PubKey) {
1096+
pkBytes, err := hex.DecodeString(pk)
1097+
if err != nil {
1098+
panic(err)
1099+
}
1100+
pubkey := &ed25519.PubKey{Key: pkBytes}
1101+
return pubkey
1102+
}

x/distribution/keeper/msg_server.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package keeper
22

33
import (
44
"context"
5+
"fmt"
56

67
"github.com/hashicorp/go-metrics"
78

@@ -200,6 +201,36 @@ func (k msgServer) DepositValidatorRewardsPool(ctx context.Context, msg *types.M
200201
return nil, err
201202
}
202203

204+
// make sure the reward pool isn't already full.
205+
if !validator.GetTokens().IsZero() {
206+
rewards, err := k.GetValidatorCurrentRewards(ctx, valAddr)
207+
if err != nil {
208+
return nil, err
209+
}
210+
current := rewards.Rewards
211+
historical, err := k.GetValidatorHistoricalRewards(ctx, valAddr, rewards.Period-1)
212+
if err != nil {
213+
return nil, err
214+
}
215+
if !historical.CumulativeRewardRatio.IsZero() {
216+
rewardRatio := historical.CumulativeRewardRatio
217+
var panicErr error
218+
func() {
219+
defer func() {
220+
if r := recover(); r != nil {
221+
panicErr = fmt.Errorf("deposit is too large: %v", r)
222+
}
223+
}()
224+
rewardRatio.Add(current...)
225+
}()
226+
227+
// Check if the deferred function caught a panic
228+
if panicErr != nil {
229+
return nil, fmt.Errorf("unable to deposit coins: %w", panicErr)
230+
}
231+
}
232+
}
233+
203234
logger := k.Logger(ctx)
204235
logger.Info(
205236
"transferred from rewards to validator rewards pool",

0 commit comments

Comments
 (0)