Skip to content

Commit

Permalink
fix(x/auth/vesting): panic on overflowing & negative EndTimes for Per…
Browse files Browse the repository at this point in the history
…iodicVestingAccount (#16733)

(cherry picked from commit d90abbe)

# Conflicts:
#	CHANGELOG.md
  • Loading branch information
odeke-em authored and mergify[bot] committed Jun 28, 2023
1 parent 84256a0 commit 78e2234
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 1 deletion.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,30 @@ Ref: https://keepachangelog.com/en/1.0.0/

* (x/staking) [#16324](https://github.com/cosmos/cosmos-sdk/pull/16324) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`. Notable changes:
* `Validator` method now returns `types.ErrNoValidatorFound` instead of `nil` when not found.
<<<<<<< HEAD
=======
* (x/distribution) [#16440](https://github.com/cosmos/cosmos-sdk/pull/16440) use collections for `DelegatorWithdrawAddresState`:
* remove `Keeper`: `SetDelegatorWithdrawAddr`, `DeleteDelegatorWithdrawAddr`, `IterateDelegatorWithdrawAddrs`.
* (x/distribution) [#16459](https://github.com/cosmos/cosmos-sdk/pull/16459) use collections for `ValidatorCurrentRewards` state management:
* remove `Keeper`: `IterateValidatorCurrentRewards`, `GetValidatorCurrentRewards`, `SetValidatorCurrentRewards`, `DeleteValidatorCurrentRewards`
* (x/authz) [#16509](https://github.com/cosmos/cosmos-sdk/pull/16509) `AcceptResponse` has been moved to sdk/types/authz and the `Updated` field is now of the type `sdk.Msg` instead of `authz.Authorization`.
* (x/distribution) [#16483](https://github.com/cosmos/cosmos-sdk/pull/16483) use collections for `DelegatorStartingInfo` state management:
* remove `Keeper`: `IterateDelegatorStartingInfo`, `GetDelegatorStartingInfo`, `SetDelegatorStartingInfo`, `DeleteDelegatorStartingInfo`, `HasDelegatorStartingInfo`
* (x/distribution) [#16571](https://github.com/cosmos/cosmos-sdk/pull/16571) use collections for `ValidatorAccumulatedCommission` state management:
* remove `Keeper`: `IterateValidatorAccumulatedCommission`, `GetValidatorAccumulatedCommission`, `SetValidatorAccumulatedCommission`, `DeleteValidatorAccumulatedCommission`
* (x/distribution) [#16590](https://github.com/cosmos/cosmos-sdk/pull/16590) use collections for `ValidatorOutstandingRewards` state management:
* remove `Keeper`: `IterateValidatorOutstandingRewards`, `GetValidatorOutstandingRewards`, `SetValidatorOutstandingRewards`, `DeleteValidatorOutstandingRewards`
* (x/distribution) [#16607](https://github.com/cosmos/cosmos-sdk/pull/16607) use collections for `ValidatorHistoricalRewards` state management:
* remove `Keeper`: `IterateValidatorHistoricalRewards`, `GetValidatorHistoricalRewards`, `SetValidatorHistoricalRewards`, `DeleteValidatorHistoricalRewards`, `DeleteValidatorHistoricalReward`, `DeleteAllValidatorHistoricalRewards`

### Bug Fixes

* (x/auth/vesting) [#16733](https://github.com/cosmos/cosmos-sdk/pull/16733) panic on overflowing and negative EndTimes when creating a PeriodicVestingAccount
* [#16547](https://github.com/cosmos/cosmos-sdk/pull/16547) Ensure a transaction's gas limit cannot exceed the block gas limit.
* (x/auth/types) [#16554](https://github.com/cosmos/cosmos-sdk/pull/16554) `ModuleAccount.Validate` now reports a nil `.BaseAccount` instead of panicking.
* (baseapp) [#16613](https://github.com/cosmos/cosmos-sdk/pull/16613) Ensure each message in a transaction has a registered handler, otherwise `CheckTx` will fail.
* [#16639](https://github.com/cosmos/cosmos-sdk/pull/16639) Make sure we don't execute blocks beyond the halt height.
>>>>>>> d90abbea5 (fix(x/auth/vesting): panic on overflowing & negative EndTimes for PeriodicVestingAccount (#16733))
## [v0.50.0-alpha.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.0-alpha.0) - 2023-06-07

Expand Down
5 changes: 5 additions & 0 deletions x/auth/vesting/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ func (s msgServer) CreatePeriodicVestingAccount(goCtx context.Context, msg *type
baseAccount = s.AccountKeeper.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount)
vestingAccount := types.NewPeriodicVestingAccount(baseAccount, totalCoins.Sort(), msg.StartTime, msg.VestingPeriods)

// Enforce and sanity check that we don't have any negative endTime.
if bva := vestingAccount.BaseVestingAccount; bva != nil && bva.EndTime < 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "cumulative endtime is negative")
}

s.AccountKeeper.SetAccount(ctx, vestingAccount)

defer func() {
Expand Down
9 changes: 8 additions & 1 deletion x/auth/vesting/types/vesting_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"errors"
"fmt"
"time"

"cosmossdk.io/math"
Expand Down Expand Up @@ -259,9 +260,15 @@ func NewPeriodicVestingAccountRaw(bva *BaseVestingAccount, startTime int64, peri
// NewPeriodicVestingAccount returns a new PeriodicVestingAccount
func NewPeriodicVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, startTime int64, periods Periods) *PeriodicVestingAccount {
endTime := startTime
for _, p := range periods {
for i, p := range periods {
if p.Length < 0 {
panic(fmt.Sprintf("period #%d has a negative length: %d", i, p.Length))
}
endTime += p.Length
}
if endTime < 0 || endTime < startTime {
panic("cumulative endTime overflowed, and/or is less than startTime")
}
baseVestingAcc := &BaseVestingAccount{
BaseAccount: baseAcc,
OriginalVesting: originalVesting,
Expand Down
61 changes: 61 additions & 0 deletions x/auth/vesting/types/vesting_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,67 @@ func TestGetVestedCoinsPeriodicVestingAcc(t *testing.T) {
require.Equal(t, origCoins, vestedCoins)
}

func TestOverflowAndNegativeVestedCoinsPeriods(t *testing.T) {
now := tmtime.Now()
tests := []struct {
name string
periods []types.Period
wantPanic string
}{
{
"negative .Length",
types.Periods{
types.Period{Length: -1, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}},
types.Period{Length: 6 * 60 * 60, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}},
},
"period #0 has a negative length: -1",
},
{
"overflow after .Length additions",
types.Periods{
types.Period{Length: 9223372036854775108, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}},
types.Period{Length: 6 * 60 * 60, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}},
},
"cumulative endTime overflowed, and/or is less than startTime",
},
{
"good periods that are not negative nor overflow",
types.Periods{
types.Period{Length: now.Unix() - 1000, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}},
types.Period{Length: 60, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}},
},
"",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bacc, origCoins := initBaseAccount()
defer func() {
r := recover()
if r == nil {
if tt.wantPanic != "" {
t.Fatalf("expected a panic with substring: %q", tt.wantPanic)
}
return
}

// Otherwise ensure we match the panic substring.
require.Contains(t, r, tt.wantPanic)
}()

pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), tt.periods)
if pva == nil {
return
}

if pbva := pva.BaseVestingAccount; pbva.EndTime < 0 {
t.Fatalf("Unfortunately we still have negative .EndTime :-(: %d", pbva.EndTime)
}
})
}
}

func TestGetVestingCoinsPeriodicVestingAcc(t *testing.T) {
now := tmtime.Now()
endTime := now.Add(24 * time.Hour)
Expand Down

0 comments on commit 78e2234

Please sign in to comment.