Skip to content

Commit

Permalink
consumer: update keeper to implement v50 Staking keeper
Browse files Browse the repository at this point in the history
  • Loading branch information
MSalopek committed Oct 13, 2023
1 parent e14e056 commit 907890f
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 52 deletions.
2 changes: 1 addition & 1 deletion app/consumer/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ func New(
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)),
capability.NewAppModule(appCodec, *app.CapabilityKeeper, false),
crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.ConsumerKeeper, app.GetSubspace(slashingtypes.ModuleName)),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.ConsumerKeeper, app.GetSubspace(slashingtypes.ModuleName), app.interfaceRegistry),
upgrade.NewAppModule(&app.UpgradeKeeper, app.AccountKeeper.AddressCodec()),
evidence.NewAppModule(app.EvidenceKeeper),
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
Expand Down
4 changes: 3 additions & 1 deletion x/ccv/consumer/keeper/hooks.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package keeper

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"

ccv "github.com/cosmos/interchain-security/v3/x/ccv/types"
Expand All @@ -18,7 +20,7 @@ func (k Keeper) Hooks() Hooks {
return Hooks{k}
}

func (k Keeper) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error {
func (k Keeper) AfterValidatorBonded(ctx context.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) error {
if k.hooks != nil {
err := k.hooks.AfterValidatorBonded(ctx, consAddr, nil)
return err
Expand Down
18 changes: 15 additions & 3 deletions x/ccv/consumer/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
"context"
"encoding/binary"
"fmt"
"reflect"
Expand Down Expand Up @@ -177,6 +178,16 @@ func (k *Keeper) SetHooks(sh ccv.ConsumerHooks) *Keeper {
return k
}

// ValidatorAddressCodec returns the app validator address codec.
func (k Keeper) ValidatorAddressCodec() addresscodec.Codec {
return k.validatorAddressCodec
}

// ConsensusAddressCodec returns the app consensus address codec.
func (k Keeper) ConsensusAddressCodec() addresscodec.Codec {
return k.consensusAddressCodec
}

// ChanCloseInit defines a wrapper function for the channel Keeper's function
// Following ICS 004: https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics#closing-handshake
func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error {
Expand Down Expand Up @@ -600,8 +611,9 @@ func (k Keeper) GetAllCCValidator(ctx sdk.Context) (validators []types.CrossChai
}

// Implement from stakingkeeper interface
func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []stakingtypes.Validator) {
store := ctx.KVStore(k.storeKey)
func (k Keeper) GetAllValidators(ctx context.Context) (validators []stakingtypes.Validator, err error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
store := sdkCtx.KVStore(k.storeKey)

iterator := storetypes.KVStorePrefixIterator(store, stakingtypes.ValidatorsKey)
defer iterator.Close()
Expand All @@ -611,7 +623,7 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []stakingtypes.Val
validators = append(validators, validator)
}

return validators
return validators, err
}

// getAndIncrementPendingPacketsIdx returns the current pending packets index and increments it.
Expand Down
7 changes: 4 additions & 3 deletions x/ccv/consumer/keeper/params.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
"context"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -36,9 +37,9 @@ func (k Keeper) SetParams(ctx sdk.Context, params ccvtypes.Params) {
// GetParams implements StakingKeeper GetParams interface method
// it returns an a empty stakingtypes.Params struct
// NOTE: this method must be implemented on the consumer keeper because the evidence module keeper
// in cosmos-sdk v0.47 requires this exact method with this exact signature to be available on the StakingKeepr
func (k Keeper) GetParams(ctx sdk.Context) stakingtypes.Params {
return stakingtypes.Params{}
// in cosmos-sdk v0.50 requires this exact method with this exact signature to be available on the StakingKeepr
func (k Keeper) GetParams(context.Context) (stakingtypes.Params, error) {
return stakingtypes.Params{}, nil
}

// GetEnabled returns the enabled flag for the consumer module
Expand Down
102 changes: 59 additions & 43 deletions x/ccv/consumer/keeper/validators.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package keeper

import (
"context"
"errors"
"time"

"cosmossdk.io/math"
Expand Down Expand Up @@ -74,27 +76,29 @@ func (k Keeper) ApplyCCValidatorChanges(ctx sdk.Context, changes []abci.Validato
// IterateValidators - unimplemented on CCV keeper but perform a no-op in order to pass the slashing module InitGenesis.
// It is allowed since the condition verifying validator public keys in HandleValidatorSignature (x/slashing/keeper/infractions.go) is removed
// therefore it isn't required to store any validator public keys to the slashing states during genesis.
func (k Keeper) IterateValidators(sdk.Context, func(index int64, validator stakingtypes.ValidatorI) (stop bool)) {
func (k Keeper) IterateValidators(context.Context, func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error {
return nil
}

// Validator - unimplemented on CCV keeper
func (k Keeper) Validator(ctx sdk.Context, addr sdk.ValAddress) stakingtypes.ValidatorI {
func (k Keeper) Validator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.ValidatorI, error) {
panic("unimplemented on CCV keeper")
}

// IsJailed returns the outstanding slashing flag for the given validator adddress
func (k Keeper) IsValidatorJailed(ctx sdk.Context, addr sdk.ConsAddress) (bool, error) {
func (k Keeper) IsValidatorJailed(ctx context.Context, addr sdk.ConsAddress) (bool, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
// if the changeover is not complete for prev standalone chain,
// return the standalone staking keeper's jailed status
if k.IsPrevStandaloneChain(ctx) && !k.ChangeoverIsComplete(ctx) {
return k.standaloneStakingKeeper.IsValidatorJailed(ctx, addr)
if k.IsPrevStandaloneChain(sdkCtx) && !k.ChangeoverIsComplete(sdkCtx) {
return k.standaloneStakingKeeper.IsValidatorJailed(sdkCtx, addr)
}
// Otherwise, return the ccv consumer keeper's notion of a validator being jailed
return k.OutstandingDowntime(ctx, addr), nil
return k.OutstandingDowntime(sdkCtx, addr), nil
}

// ValidatorByConsAddr returns an empty validator
func (k Keeper) ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) stakingtypes.ValidatorI {
func (k Keeper) ValidatorByConsAddr(context.Context, sdk.ConsAddress) (stakingtypes.ValidatorI, error) {
/*
NOTE:
Expand All @@ -105,27 +109,28 @@ func (k Keeper) ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) stakingtypes.V
Also, the slashing module will cal lthis function when it observes downtime. In that case
the only requirement on the returned value is that it isn't null.
*/
return stakingtypes.Validator{}
return stakingtypes.Validator{}, nil
}

// Calls SlashWithInfractionReason with Infraction_INFRACTION_UNSPECIFIED.
// ConsumerKeeper must implement StakingKeeper interface.
// This function should not be called anywhere
func (k Keeper) Slash(ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec) (math.Int, error) {
func (k Keeper) Slash(ctx context.Context, addr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec) (math.Int, error) {
return k.SlashWithInfractionReason(ctx, addr, infractionHeight, power, slashFactor, stakingtypes.Infraction_INFRACTION_UNSPECIFIED)
}

// Slash queues a slashing request for the the provider chain
// All queued slashing requests will be cleared in EndBlock
// Called by Slashing keeper in SlashWithInfractionReason
func (k Keeper) SlashWithInfractionReason(ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec, infraction stakingtypes.Infraction) (math.Int, error) {
func (k Keeper) SlashWithInfractionReason(ctx context.Context, addr sdk.ConsAddress, infractionHeight, power int64, slashFactor math.LegacyDec, infraction stakingtypes.Infraction) (math.Int, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
if infraction == stakingtypes.Infraction_INFRACTION_UNSPECIFIED {
return math.NewInt(0), nil
}

// If this is a previously standalone chain and infraction happened before the changeover was completed,
// slash only on the standalone staking keeper.
if k.IsPrevStandaloneChain(ctx) && infractionHeight < k.FirstConsumerHeight(ctx) {
if k.IsPrevStandaloneChain(sdkCtx) && infractionHeight < k.FirstConsumerHeight(sdkCtx) {
// Slash for a standalone chain does not require an infraction reason so we pass in Infraction_INFRACTION_UNSPECIFIED
return k.standaloneStakingKeeper.SlashWithInfractionReason(ctx, addr, infractionHeight, power, slashFactor, stakingtypes.Infraction_INFRACTION_UNSPECIFIED)
}
Expand All @@ -135,19 +140,19 @@ func (k Keeper) SlashWithInfractionReason(ctx sdk.Context, addr sdk.ConsAddress,
// if this is a downtime infraction and the validator is allowed to
// soft opt out, do not queue a slash packet
if infraction == stakingtypes.Infraction_INFRACTION_DOWNTIME {
if power < k.GetSmallestNonOptOutPower(ctx) {
if power < k.GetSmallestNonOptOutPower(sdkCtx) {
// soft opt out
k.Logger(ctx).Debug("soft opt out",
k.Logger(sdkCtx).Debug("soft opt out",
"validator", addr,
"power", power,
)
return math.NewInt(0), nil
}
}
// get VSC ID for infraction height
vscID := k.GetHeightValsetUpdateID(ctx, uint64(infractionHeight))
vscID := k.GetHeightValsetUpdateID(sdkCtx, uint64(infractionHeight))

k.Logger(ctx).Debug("vscID obtained from mapped infraction height",
k.Logger(sdkCtx).Debug("vscID obtained from mapped infraction height",
"infraction height", infractionHeight,
"vscID", vscID,
)
Expand All @@ -156,7 +161,7 @@ func (k Keeper) SlashWithInfractionReason(ctx sdk.Context, addr sdk.ConsAddress,
// everything else is just here to implement StakingKeeper interface
// IBC packets are created from slash data and sent to the provider during EndBlock
k.QueueSlashPacket(
ctx,
sdkCtx,
abci.Validator{
Address: addr.Bytes(),
Power: power,
Expand All @@ -174,64 +179,70 @@ func (k Keeper) SlashWithInfractionReason(ctx sdk.Context, addr sdk.ConsAddress,
// This method should be a no-op even during a standalone to consumer changeover.
// Once the upgrade has happened as a part of the changeover,
// the provider validator set will soon be in effect, and jailing is n/a.
func (k Keeper) Jail(ctx sdk.Context, addr sdk.ConsAddress) {}
func (k Keeper) Jail(context.Context, sdk.ConsAddress) error { return nil }

// Unjail - unimplemented on CCV keeper
//
// This method should be a no-op even during a standalone to consumer changeover.
// Once the upgrade has happened as a part of the changeover,
// the provider validator set will soon be in effect, and jailing is n/a.
func (k Keeper) Unjail(sdk.Context, sdk.ConsAddress) {}
func (k Keeper) Unjail(context.Context, sdk.ConsAddress) error { return nil }

// Delegation - unimplemented on CCV keeper
func (k Keeper) Delegation(sdk.Context, sdk.AccAddress, sdk.ValAddress) stakingtypes.DelegationI {
func (k Keeper) Delegation(ctx context.Context, addr sdk.AccAddress, valAddr sdk.ValAddress) (stakingtypes.DelegationI, error) {
panic("unimplemented on CCV keeper")
}

// MaxValidators - unimplemented on CCV keeper
func (k Keeper) MaxValidators(sdk.Context) uint32 {
func (k Keeper) MaxValidators(context.Context) (uint32, error) {
panic("unimplemented on CCV keeper")
}

// UnbondingTime returns consumer unbonding period, satisfying the staking keeper interface
func (k Keeper) UnbondingTime(ctx sdk.Context) time.Duration {
return k.GetUnbondingPeriod(ctx)
func (k Keeper) UnbondingTime(ctx context.Context) (time.Duration, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
return k.GetUnbondingPeriod(sdkCtx), nil
}

// GetHistoricalInfo gets the historical info at a given height
func (k Keeper) GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) {
store := ctx.KVStore(k.storeKey)
func (k Keeper) GetHistoricalInfo(ctx context.Context, height int64) (stakingtypes.HistoricalInfo, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
store := sdkCtx.KVStore(k.storeKey)
key := types.HistoricalInfoKey(height)

value := store.Get(key)
if value == nil {
return stakingtypes.HistoricalInfo{}, false
return stakingtypes.HistoricalInfo{}, stakingtypes.ErrNoHistoricalInfo
}

return stakingtypes.MustUnmarshalHistoricalInfo(k.cdc, value), true
return stakingtypes.UnmarshalHistoricalInfo(k.cdc, value)
}

// SetHistoricalInfo sets the historical info at a given height
func (k Keeper) SetHistoricalInfo(ctx sdk.Context, height int64, hi *stakingtypes.HistoricalInfo) {
store := ctx.KVStore(k.storeKey)
func (k Keeper) SetHistoricalInfo(ctx context.Context, height int64, hi *stakingtypes.HistoricalInfo) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
store := sdkCtx.KVStore(k.storeKey)
key := types.HistoricalInfoKey(height)
value := k.cdc.MustMarshal(hi)

store.Set(key, value)
}

// DeleteHistoricalInfo deletes the historical info at a given height
func (k Keeper) DeleteHistoricalInfo(ctx sdk.Context, height int64) {
store := ctx.KVStore(k.storeKey)
func (k Keeper) DeleteHistoricalInfo(ctx context.Context, height int64) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)
store := sdkCtx.KVStore(k.storeKey)
key := types.HistoricalInfoKey(height)

store.Delete(key)
return nil
}

// TrackHistoricalInfo saves the latest historical-info and deletes the oldest
// heights that are below pruning height
func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) {
numHistoricalEntries := k.GetHistoricalEntries(ctx)
func (k Keeper) TrackHistoricalInfo(ctx context.Context) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)
numHistoricalEntries := k.GetHistoricalEntries(sdkCtx)

// Prune store to ensure we only have parameter-defined historical entries.
// In most cases, this will involve removing a single historical entry.
Expand All @@ -240,23 +251,27 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) {
// Since the entries to be deleted are always in a continuous range, we can iterate
// over the historical entries starting from the most recent version to be pruned
// and then return at the first empty entry.
for i := ctx.BlockHeight() - numHistoricalEntries; i >= 0; i-- {
_, found := k.GetHistoricalInfo(ctx, i)
if found {
k.DeleteHistoricalInfo(ctx, i)
} else {
break
for i := sdkCtx.BlockHeight() - numHistoricalEntries; i >= 0; i-- {
_, err := k.GetHistoricalInfo(ctx, i)
if err != nil {
if errors.Is(err, stakingtypes.ErrNoHistoricalInfo) {
break
}
return err
}
if err = k.DeleteHistoricalInfo(ctx, i); err != nil {
return err
}
}

// if there is no need to persist historicalInfo, return
if numHistoricalEntries == 0 {
return
return nil
}

// Create HistoricalInfo struct
lastVals := []stakingtypes.Validator{}
for _, v := range k.GetAllCCValidator(ctx) {
for _, v := range k.GetAllCCValidator(sdkCtx) {
pk, err := v.ConsPubKey()
if err != nil {
// This should never happen as the pubkey is assumed
Expand All @@ -279,10 +294,11 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) {
}

// Create historical info entry which sorts the validator set by voting power
historicalEntry := stakingtypes.NewHistoricalInfo(ctx.BlockHeader(), stakingtypes.Validators{Validators: lastVals, ValidatorCodec: k.validatorAddressCodec}, sdk.DefaultPowerReduction)
historicalEntry := stakingtypes.NewHistoricalInfo(sdkCtx.BlockHeader(), stakingtypes.Validators{Validators: lastVals, ValidatorCodec: k.validatorAddressCodec}, sdk.DefaultPowerReduction)

// Set latest HistoricalInfo at current height
k.SetHistoricalInfo(ctx, ctx.BlockHeight(), &historicalEntry)
k.SetHistoricalInfo(ctx, sdkCtx.BlockHeight(), &historicalEntry)
return nil
}

// MustGetCurrentValidatorsAsABCIUpdates gets all cross-chain validators converted
Expand Down Expand Up @@ -310,6 +326,6 @@ func (k Keeper) MustGetCurrentValidatorsAsABCIUpdates(ctx sdk.Context) []abci.Va

// implement interface method needed for x/genutil in sdk v47
// returns empty updates and err
func (k Keeper) ApplyAndReturnValidatorSetUpdates(sdk.Context) (updates []abci.ValidatorUpdate, err error) {
func (k Keeper) ApplyAndReturnValidatorSetUpdates(context.Context) (updates []abci.ValidatorUpdate, err error) {
return
}
2 changes: 1 addition & 1 deletion x/ccv/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ type DistributionKeeper interface {

// ConsumerHooks event hooks for newly bonded cross-chain validators
type ConsumerHooks interface {
AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddresses sdk.ValAddress) error
AfterValidatorBonded(ctx context.Context, consAddr sdk.ConsAddress, valAddresses sdk.ValAddress) error
}

// BankKeeper defines the expected interface needed to retrieve account balances.
Expand Down

0 comments on commit 907890f

Please sign in to comment.