Skip to content

Commit

Permalink
Implement cap on uncompleted corks per validator to prevent storage D…
Browse files Browse the repository at this point in the history
…oS (#218)

* Implement cap on uncompleted corks per validator to prevent storage DoS

* Fix proto binding merge error

* Run gofmt

* manually call Validate on the genesis states

* point to gravity v4.0.0 release

* fix casing for some cellars, add Turbo EETH

* update slices sizes with new cellar added

* log the ICA host param update

* actually validate the minimum USD value parameter

* normalize cellars with eth mainnet chain ID prefix

* add arbitrum test cellar to pubsub

* Add test arbitrum cellar to axelarcork

* some comments

* loosen ProofURL validation

* fix auction params test

* set LastUpdatedBlock for token prices in v7 upgrade

* ledger support for cork

* GetSignBytes for cork

* appease linter

---------

Co-authored-by: Eric Bolten <[email protected]>
  • Loading branch information
cbrit and EricBolten authored Dec 15, 2023
1 parent a2d191e commit 1498c8e
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 49 deletions.
1 change: 1 addition & 0 deletions integration_tests/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ func (s *IntegrationTestSuite) initGenesis() {
// we add the first validator address as a cellar so that it will trigger the cellarfees hook
// when we send test fees
corkGenState.CellarIds = corktypes.CellarIDSet{Ids: []string{unusedGenesisContract.String(), s.chain.validators[0].ethereumKey.address}}
corkGenState.Params = corktypes.DefaultParams()
corkGenState.Params.VoteThreshold = corkVoteThreshold
bz, err = cdc.MarshalJSON(&corkGenState)
s.Require().NoError(err)
Expand Down
1 change: 1 addition & 0 deletions proto/cork/v2/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ message Params {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
uint64 max_corks_per_validator = 2;
}
2 changes: 1 addition & 1 deletion x/auction/keeper/sdk_module_mocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ func (suite *KeeperTestSuite) mockSendCoinsFromAccountToModule(ctx sdk.Context,

func (suite *KeeperTestSuite) mockSendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, receiverAcct sdk.AccAddress, amt sdk.Coins) {
suite.bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, senderModule, receiverAcct, amt).Return(nil)
}
}
34 changes: 34 additions & 0 deletions x/cork/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"bytes"
"encoding/binary"

"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
Expand Down Expand Up @@ -297,6 +298,7 @@ func (k Keeper) GetApprovedScheduledCorks(ctx sdk.Context) (approvedCorks []type
}

k.DeleteScheduledCork(ctx, currentBlockHeight, id, val, addr)
k.DecrementValidatorCorkCount(ctx, val)

return false
})
Expand Down Expand Up @@ -358,3 +360,35 @@ func (k Keeper) HasCellarID(ctx sdk.Context, address common.Address) (found bool

return found
}

///////////////////////////
// Validator Cork counts //
///////////////////////////

func (k Keeper) GetValidatorCorkCount(ctx sdk.Context, val sdk.ValAddress) (count uint64) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.GetValidatorCorkCountKey(val))
if len(bz) == 0 {
return 0
}

return binary.BigEndian.Uint64(bz)
}

func (k Keeper) SetValidatorCorkCount(ctx sdk.Context, val sdk.ValAddress, count uint64) {
bz := make([]byte, 8)
binary.BigEndian.PutUint64(bz, count)
ctx.KVStore(k.storeKey).Set(types.GetValidatorCorkCountKey(val), bz)
}

func (k Keeper) IncrementValidatorCorkCount(ctx sdk.Context, val sdk.ValAddress) {
count := k.GetValidatorCorkCount(ctx, val)
k.SetValidatorCorkCount(ctx, val, count+1)
}

func (k Keeper) DecrementValidatorCorkCount(ctx sdk.Context, val sdk.ValAddress) {
count := k.GetValidatorCorkCount(ctx, val)
if count > 0 {
k.SetValidatorCorkCount(ctx, val, count-1)
}
}
1 change: 1 addition & 0 deletions x/cork/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (k Keeper) ScheduleCork(c context.Context, msg *types.MsgScheduleCorkReques
}

corkID := k.SetScheduledCork(ctx, msg.BlockHeight, validatorAddr, *msg.Cork)
k.IncrementValidatorCorkCount(ctx, validatorAddr)

ctx.EventManager().EmitEvents(
sdk.Events{
Expand Down
4 changes: 2 additions & 2 deletions x/cork/mock/sdk_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions x/cork/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (

// x/cork module sentinel errors
var (
ErrInvalidEthereumAddress = errorsmod.Register(ModuleName, 2, "invalid ethereum address")
ErrUnmanagedCellarAddress = errorsmod.Register(ModuleName, 3, "cork sent to address that has not passed governance")
ErrEmptyContractCall = errorsmod.Register(ModuleName, 4, "cork has an empty contract call body")
ErrSchedulingInThePast = errorsmod.Register(ModuleName, 5, "cork is trying to be scheduled for a block that has already passed")
ErrInvalidJSON = errorsmod.Register(ModuleName, 6, "invalid json")
ErrInvalidEthereumAddress = errorsmod.Register(ModuleName, 2, "invalid ethereum address")
ErrUnmanagedCellarAddress = errorsmod.Register(ModuleName, 3, "cork sent to address that has not passed governance")
ErrEmptyContractCall = errorsmod.Register(ModuleName, 4, "cork has an empty contract call body")
ErrSchedulingInThePast = errorsmod.Register(ModuleName, 5, "cork is trying to be scheduled for a block that has already passed")
ErrInvalidJSON = errorsmod.Register(ModuleName, 6, "invalid json")
ErrValidatorCorkCapacityReached = errorsmod.Register(ModuleName, 7, "validator cork capacity reached")
)
93 changes: 65 additions & 28 deletions x/cork/types/genesis.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions x/cork/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ const (

// CorkResultPrefix - <prefix><id> -> CorkResult
CorkResultPrefix

// ValidatorCorkCountKey - <prefix><val_address> -> uint64(count)
ValidatorCorkCountKey
)

// GetCorkForValidatorAddressKey returns the key for a validators vote for a given address
Expand Down Expand Up @@ -81,3 +84,7 @@ func GetCorkResultPrefix() []byte {
func GetCorkResultKey(id []byte) []byte {
return append(GetCorkResultPrefix(), id...)
}

func GetValidatorCorkCountKey(val sdk.ValAddress) []byte {
return append([]byte{ValidatorCorkCountKey}, val.Bytes()...)
}
25 changes: 22 additions & 3 deletions x/cork/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import (

// Parameter keys
var (
KeyVotePeriod = []byte("voteperiod")
KeyVoteThreshold = []byte("votethreshold")
KeyVotePeriod = []byte("voteperiod")
KeyVoteThreshold = []byte("votethreshold")
KeyMaxCorksPerValidator = []byte("maxcorkspervalidator")
)

var _ paramtypes.ParamSet = &Params{}
Expand All @@ -25,14 +26,16 @@ func ParamKeyTable() paramtypes.KeyTable {
func DefaultParams() Params {
return Params{
// Deprecated
VoteThreshold: sdk.NewDecWithPrec(67, 2), // 67%
VoteThreshold: sdk.NewDecWithPrec(67, 2), // 67%
MaxCorksPerValidator: 1000,
}
}

// ParamSetPairs returns the parameter set pairs.
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(KeyVoteThreshold, &p.VoteThreshold, validateVoteThreshold),
paramtypes.NewParamSetPair(KeyMaxCorksPerValidator, &p.MaxCorksPerValidator, validateMaxCorksPerValidator),
}
}

Expand All @@ -41,6 +44,9 @@ func (p *Params) ValidateBasic() error {
if err := validateVoteThreshold(p.VoteThreshold); err != nil {
return err
}
if err := validateMaxCorksPerValidator(p.MaxCorksPerValidator); err != nil {
return err
}
return nil
}

Expand All @@ -60,3 +66,16 @@ func validateVoteThreshold(i interface{}) error {

return nil
}

func validateMaxCorksPerValidator(i interface{}) error {
maxCorksPerValidator, ok := i.(uint64)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}

if maxCorksPerValidator == 0 {
return errors.New("max corks per validator cannot be 0")
}

return nil
}
19 changes: 9 additions & 10 deletions x/cork/types/proposal.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1498c8e

Please sign in to comment.