From e1906aaba1b9e53bf42d16367b6aab818448b1a9 Mon Sep 17 00:00:00 2001 From: mpoke Date: Wed, 6 Nov 2024 14:22:35 +0100 Subject: [PATCH] remove provider changes and fix conflicts --- ...rds.md => 2387-add-memo-to-ICS-rewards.md} | 3 +- ...rds.md => 2387-add-memo-to-ICS-rewards.md} | 3 +- UPGRADING.md | 8 +- x/ccv/provider/ibc_middleware.go | 69 -- x/ccv/provider/keeper/consumer_lifecycle.go | 663 ----------- .../keeper/consumer_lifecycle_test.go | 1046 ----------------- x/ccv/provider/keeper/grpc_query.go | 50 - x/ccv/provider/types/errors.go | 36 - x/ccv/provider/types/msg.go | 463 -------- x/ccv/provider/types/msg_test.go | 546 --------- x/ccv/provider/types/tx.pb.go | 2 +- x/ccv/types/errors.go | 7 +- x/ccv/types/shared_consumer.pb.go | 62 +- x/ccv/types/shared_params.go | 5 - x/ccv/types/shared_params_test.go | 2 +- 15 files changed, 16 insertions(+), 2949 deletions(-) rename .changelog/unreleased/features/{2290-add-memo-to-ICS-rewards.md => 2387-add-memo-to-ICS-rewards.md} (51%) rename .changelog/unreleased/state-breaking/{2290-add-memo-to-ICS-rewards.md => 2387-add-memo-to-ICS-rewards.md} (51%) delete mode 100644 x/ccv/provider/keeper/consumer_lifecycle.go delete mode 100644 x/ccv/provider/keeper/consumer_lifecycle_test.go diff --git a/.changelog/unreleased/features/2290-add-memo-to-ICS-rewards.md b/.changelog/unreleased/features/2387-add-memo-to-ICS-rewards.md similarity index 51% rename from .changelog/unreleased/features/2290-add-memo-to-ICS-rewards.md rename to .changelog/unreleased/features/2387-add-memo-to-ICS-rewards.md index 421967ddab..ec7cad68fa 100644 --- a/.changelog/unreleased/features/2290-add-memo-to-ICS-rewards.md +++ b/.changelog/unreleased/features/2387-add-memo-to-ICS-rewards.md @@ -1,4 +1,3 @@ - `[x/consumer]` Populate the memo on the IBC transfer packets used to send ICS rewards. with the required consumer chain Id to identify the consumer to the provider. -- `[x/provider]` Identify the source of ICS rewards from the IBC transfer packet memo. - ([\#2290](https://github.com/cosmos/interchain-security/pull/2290)) \ No newline at end of file + ([\#2387](https://github.com/cosmos/interchain-security/pull/2387)) \ No newline at end of file diff --git a/.changelog/unreleased/state-breaking/2290-add-memo-to-ICS-rewards.md b/.changelog/unreleased/state-breaking/2387-add-memo-to-ICS-rewards.md similarity index 51% rename from .changelog/unreleased/state-breaking/2290-add-memo-to-ICS-rewards.md rename to .changelog/unreleased/state-breaking/2387-add-memo-to-ICS-rewards.md index 421967ddab..ec7cad68fa 100644 --- a/.changelog/unreleased/state-breaking/2290-add-memo-to-ICS-rewards.md +++ b/.changelog/unreleased/state-breaking/2387-add-memo-to-ICS-rewards.md @@ -1,4 +1,3 @@ - `[x/consumer]` Populate the memo on the IBC transfer packets used to send ICS rewards. with the required consumer chain Id to identify the consumer to the provider. -- `[x/provider]` Identify the source of ICS rewards from the IBC transfer packet memo. - ([\#2290](https://github.com/cosmos/interchain-security/pull/2290)) \ No newline at end of file + ([\#2387](https://github.com/cosmos/interchain-security/pull/2387)) \ No newline at end of file diff --git a/UPGRADING.md b/UPGRADING.md index c0821da659..0c78c7f299 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,6 +1,10 @@ # Upgrading Replicated Security -## v5.2.x +## v5.3.x + +### Provider + +***This release does not affect the provider chains.*** ### Consumer @@ -22,6 +26,8 @@ func InitializeConsumerId(ctx sdk.Context, consumerKeeper consumerkeeper.Keeper) } ``` +## v5.2.x + ### Provider Providers using versions `v5.1.x` can upgrade to `v5.2.x`. diff --git a/x/ccv/provider/ibc_middleware.go b/x/ccv/provider/ibc_middleware.go index d90ad92f4c..d9d816ab93 100644 --- a/x/ccv/provider/ibc_middleware.go +++ b/x/ccv/provider/ibc_middleware.go @@ -12,14 +12,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" -<<<<<<< HEAD "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" -======= - "github.com/cosmos/interchain-security/v6/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/v6/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v6/x/ccv/types" ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) ) var _ porttypes.Middleware = &IBCMiddleware{} @@ -127,15 +121,12 @@ func (im IBCMiddleware) OnRecvPacket( // that the packet data is valid and can be safely // deserialized without checking errors. if ack.Success() { -<<<<<<< HEAD // execute the middleware logic only if the sender is a consumer chain consumerID, err := im.keeper.IdentifyConsumerChainIDFromIBCPacket(ctx, packet) if err != nil { return ack } -======= ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) // extract the coin info received from the packet data var data ibctransfertypes.FungibleTokenPacketData _ = types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data) @@ -146,68 +137,8 @@ func (im IBCMiddleware) OnRecvPacket( return ack } -<<<<<<< HEAD coinAmt, _ := math.NewIntFromString(data.Amount) coinDenom := GetProviderDenom(data.Denom, packet) -======= - consumerId := "" - // check if the transfer has the reward memo - if rewardMemo, err := ccvtypes.GetRewardMemoFromTransferMemo(data.Memo); err != nil { - // check if the transfer is on a channel with the same underlying - // client as the CCV channel - consumerId, err = im.keeper.IdentifyConsumerIdFromIBCPacket(ctx, packet) - if err != nil { - if data.Memo == "consumer chain rewards distribution" { - // log error message - logger.Error( - "received token transfer with ICS reward from unknown consumer", - "packet", packet.String(), - "fungibleTokenPacketData", data.String(), - "error", err.Error(), - ) - } - - return ack - } - } else { - logger.Info("transfer memo:%#+v", rewardMemo) - consumerId = rewardMemo.ConsumerId - } - - coinAmt, _ := math.NewIntFromString(data.Amount) - coinDenom := GetProviderDenom(data.Denom, packet) - chainId, err := im.keeper.GetConsumerChainId(ctx, consumerId) - if err != nil { - logger.Error( - "cannot get consumer chain id in transfer middleware", - "consumerId", consumerId, - "packet", packet.String(), - "fungibleTokenPacketData", data.String(), - "error", err.Error(), - ) - return ack - } - - logger.Info( - "received ICS rewards from consumer chain", - "consumerId", consumerId, - "chainId", chainId, - "denom", coinDenom, - "amount", data.Amount, - ) - - // initialize an empty slice to store event attributes - eventAttributes := []sdk.Attribute{} - - // add event attributes - eventAttributes = append(eventAttributes, []sdk.Attribute{ - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(types.AttributeConsumerId, consumerId), - sdk.NewAttribute(types.AttributeConsumerChainId, chainId), - sdk.NewAttribute(types.AttributeRewardDenom, coinDenom), - sdk.NewAttribute(types.AttributeRewardAmount, data.Amount), - }...) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) // verify that the coin's denom is a whitelisted consumer denom, // and if so, adds it to the consumer chain rewards allocation, diff --git a/x/ccv/provider/keeper/consumer_lifecycle.go b/x/ccv/provider/keeper/consumer_lifecycle.go deleted file mode 100644 index c578df4ff2..0000000000 --- a/x/ccv/provider/keeper/consumer_lifecycle.go +++ /dev/null @@ -1,663 +0,0 @@ -package keeper - -import ( - "fmt" - "time" - - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - - errorsmod "cosmossdk.io/errors" - storetypes "cosmossdk.io/store/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - abci "github.com/cometbft/cometbft/abci/types" - tmtypes "github.com/cometbft/cometbft/types" - - "github.com/cosmos/interchain-security/v6/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/v6/x/ccv/types" -) - -// PrepareConsumerForLaunch prepares to move the launch of a consumer chain from the previous spawn time to spawn time. -// Previous spawn time can correspond to its zero value if the validator was not previously set for launch. -func (k Keeper) PrepareConsumerForLaunch(ctx sdk.Context, consumerId string, previousSpawnTime, spawnTime time.Time) error { - if !previousSpawnTime.IsZero() { - // if this is not the first initialization and hence `previousSpawnTime` does not contain the zero value of `Time` - // remove the consumer id from the previous spawn time - err := k.RemoveConsumerToBeLaunched(ctx, consumerId, previousSpawnTime) - if err != nil { - return err - } - } - return k.AppendConsumerToBeLaunched(ctx, consumerId, spawnTime) -} - -// InitializeConsumer tries to move a consumer with `consumerId` to the initialized phase. -// If successful, it returns the spawn time and true. -func (k Keeper) InitializeConsumer(ctx sdk.Context, consumerId string) (time.Time, bool) { - // a chain needs to be in the registered or initialized phase - phase := k.GetConsumerPhase(ctx, consumerId) - if phase != types.CONSUMER_PHASE_REGISTERED && phase != types.CONSUMER_PHASE_INITIALIZED { - return time.Time{}, false - } - - initializationParameters, err := k.GetConsumerInitializationParameters(ctx, consumerId) - if err != nil { - return time.Time{}, false - } - - // the spawn time needs to be positive - if initializationParameters.SpawnTime.IsZero() { - return time.Time{}, false - } - - k.SetConsumerPhase(ctx, consumerId, types.CONSUMER_PHASE_INITIALIZED) - - return initializationParameters.SpawnTime, true -} - -// BeginBlockLaunchConsumers launches initialized consumers chains for which the spawn time has passed -func (k Keeper) BeginBlockLaunchConsumers(ctx sdk.Context) error { - bondedValidators := []stakingtypes.Validator{} - activeValidators := []stakingtypes.Validator{} - - consumerIds, err := k.ConsumeIdsFromTimeQueue( - ctx, - types.SpawnTimeToConsumerIdsKeyPrefix(), - k.GetConsumersToBeLaunched, - k.DeleteAllConsumersToBeLaunched, - k.AppendConsumerToBeLaunched, - 200, - ) - if err != nil { - return errorsmod.Wrapf(ccv.ErrInvalidConsumerState, "getting consumers ready to laumch: %s", err.Error()) - } - if len(consumerIds) > 0 { - // get the bonded validators from the staking module - bondedValidators, err = k.GetLastBondedValidators(ctx) - if err != nil { - return fmt.Errorf("getting last bonded validators: %w", err) - } - // get the provider active validators - activeValidators, err = k.GetLastProviderConsensusActiveValidators(ctx) - if err != nil { - return fmt.Errorf("getting last provider active validators: %w", err) - } - } - - for _, consumerId := range consumerIds { - cachedCtx, writeFn := ctx.CacheContext() - err = k.LaunchConsumer(cachedCtx, bondedValidators, activeValidators, consumerId) - if err != nil { - ctx.Logger().Error("could not launch chain", - "consumerId", consumerId, - "error", err) - - // reset spawn time to zero so that owner can try again later - initializationRecord, err := k.GetConsumerInitializationParameters(ctx, consumerId) - if err != nil { - return errorsmod.Wrapf(ccv.ErrInvalidConsumerState, - "getting initialization parameters, consumerId(%s): %s", consumerId, err.Error()) - } - initializationRecord.SpawnTime = time.Time{} - err = k.SetConsumerInitializationParameters(ctx, consumerId, initializationRecord) - if err != nil { - return fmt.Errorf("setting consumer initialization parameters, consumerId(%s): %w", consumerId, err) - } - // also set the phase to registered - k.SetConsumerPhase(ctx, consumerId, types.CONSUMER_PHASE_REGISTERED) - - continue - } - - writeFn() - } - return nil -} - -// ConsumeIdsFromTimeQueue returns from a time queue the consumer ids for which the associated time passed. -// The number of ids return is limited to 'limit'. The ids returned are removed from the time queue. -func (k Keeper) ConsumeIdsFromTimeQueue( - ctx sdk.Context, - timeQueueKeyPrefix byte, - getIds func(sdk.Context, time.Time) (types.ConsumerIds, error), - deleteAllIds func(sdk.Context, time.Time), - appendId func(sdk.Context, string, time.Time) error, - limit int, -) ([]string, error) { - store := ctx.KVStore(k.storeKey) - - result := []string{} - nextTime := []string{} - timestampsToDelete := []time.Time{} - - iterator := storetypes.KVStorePrefixIterator(store, []byte{timeQueueKeyPrefix}) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - if len(result) >= limit { - break - } - ts, err := types.ParseTime(timeQueueKeyPrefix, iterator.Key()) - if err != nil { - return result, fmt.Errorf("parsing removal time: %w", err) - } - if ts.After(ctx.BlockTime()) { - break - } - - consumerIds, err := getIds(ctx, ts) - if err != nil { - return result, - fmt.Errorf("getting consumers ids, ts(%s): %w", ts.String(), err) - } - - timestampsToDelete = append(timestampsToDelete, ts) - - availableSlots := limit - len(result) - if availableSlots >= len(consumerIds.Ids) { - // consumer all the ids - result = append(result, consumerIds.Ids...) - } else { - // consume only availableSlots - result = append(result, consumerIds.Ids[:availableSlots]...) - // and leave the others for next time - nextTime = consumerIds.Ids[availableSlots:] - break - } - } - - // remove consumers to prevent handling them twice - for i, ts := range timestampsToDelete { - deleteAllIds(ctx, ts) - if i == len(timestampsToDelete)-1 { - // for the last ts consumed, store back the ids for later - for _, consumerId := range nextTime { - err := appendId(ctx, consumerId, ts) - if err != nil { - return result, - fmt.Errorf("failed to append consumer id, consumerId(%s), ts(%s): %w", - consumerId, ts.String(), err) - } - } - } - } - - return result, nil -} - -// LaunchConsumer launches the chain with the provided consumer id by creating the consumer client and the respective -// consumer genesis file -// -// TODO add unit test for LaunchConsumer -func (k Keeper) LaunchConsumer( - ctx sdk.Context, - bondedValidators []stakingtypes.Validator, - activeValidators []stakingtypes.Validator, - consumerId string, -) error { - // compute consumer initial validator set - initialValUpdates, err := k.ComputeConsumerNextValSet(ctx, bondedValidators, activeValidators, consumerId, []types.ConsensusValidator{}) - if err != nil { - return fmt.Errorf("computing consumer next validator set, consumerId(%s): %w", consumerId, err) - } - if len(initialValUpdates) == 0 { - return fmt.Errorf("cannot launch consumer with no validator opted in, consumerId(%s)", consumerId) - } - - // create consumer genesis - genesisState, err := k.MakeConsumerGenesis(ctx, consumerId, initialValUpdates) - if err != nil { - return fmt.Errorf("creating consumer genesis state, consumerId(%s): %w", consumerId, err) - } - err = k.SetConsumerGenesis(ctx, consumerId, genesisState) - if err != nil { - return fmt.Errorf("setting consumer genesis state, consumerId(%s): %w", consumerId, err) - } - - // compute the hash of the consumer initial validator updates - updatesAsValSet, err := tmtypes.PB2TM.ValidatorUpdates(initialValUpdates) - if err != nil { - return fmt.Errorf("unable to create initial validator set from initial validator updates: %w", err) - } - valsetHash := tmtypes.NewValidatorSet(updatesAsValSet).Hash() - - // create the consumer client and the genesis - err = k.CreateConsumerClient(ctx, consumerId, valsetHash) - if err != nil { - return fmt.Errorf("crating consumer client, consumerId(%s): %w", consumerId, err) - } - - k.SetConsumerPhase(ctx, consumerId, types.CONSUMER_PHASE_LAUNCHED) - - k.Logger(ctx).Info("consumer successfully launched", - "consumerId", consumerId, - "valset size", len(initialValUpdates), - "valsetHash", string(valsetHash), - ) - - return nil -} - -// CreateConsumerClient will create the CCV client for the given consumer chain. The CCV channel must be built -// on top of the CCV client to ensure connection with the right consumer chain. -func (k Keeper) CreateConsumerClient( - ctx sdk.Context, - consumerId string, - valsetHash []byte, -) error { - initializationRecord, err := k.GetConsumerInitializationParameters(ctx, consumerId) - if err != nil { - return err - } - - phase := k.GetConsumerPhase(ctx, consumerId) - if phase != types.CONSUMER_PHASE_INITIALIZED { - return errorsmod.Wrapf(types.ErrInvalidPhase, - "cannot create client for consumer chain that is not in the Initialized phase but in phase %d: %s", phase, consumerId) - } - - chainId, err := k.GetConsumerChainId(ctx, consumerId) - if err != nil { - return err - } - - // Set minimum height for equivocation evidence from this consumer chain - k.SetEquivocationEvidenceMinHeight(ctx, consumerId, initializationRecord.InitialHeight.RevisionHeight) - - // Consumers start out with the unbonding period from the initialization parameters - consumerUnbondingPeriod := initializationRecord.UnbondingPeriod - - // Create client state by getting template client from initialization parameters - clientState := k.GetTemplateClient(ctx) - clientState.ChainId = chainId - clientState.LatestHeight = initializationRecord.InitialHeight - - trustPeriod, err := ccv.CalculateTrustPeriod(consumerUnbondingPeriod, k.GetTrustingPeriodFraction(ctx)) - if err != nil { - return err - } - clientState.TrustingPeriod = trustPeriod - clientState.UnbondingPeriod = consumerUnbondingPeriod - - // Create consensus state - consensusState := ibctmtypes.NewConsensusState( - ctx.BlockTime(), - commitmenttypes.NewMerkleRoot([]byte(ibctmtypes.SentinelRoot)), - valsetHash, - ) - - clientID, err := k.clientKeeper.CreateClient(ctx, clientState, consensusState) - if err != nil { - return err - } - k.SetConsumerClientId(ctx, consumerId, clientID) - - k.Logger(ctx).Info("consumer client created", - "consumer id", consumerId, - "client id", clientID, - ) - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeConsumerClientCreated, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(types.AttributeConsumerId, consumerId), - sdk.NewAttribute(types.AttributeConsumerChainId, chainId), - sdk.NewAttribute(clienttypes.AttributeKeyClientID, clientID), - sdk.NewAttribute(types.AttributeInitialHeight, initializationRecord.InitialHeight.String()), - sdk.NewAttribute(types.AttributeTrustingPeriod, clientState.TrustingPeriod.String()), - sdk.NewAttribute(types.AttributeUnbondingPeriod, clientState.UnbondingPeriod.String()), - sdk.NewAttribute(types.AttributeValsetHash, string(valsetHash)), - ), - ) - - return nil -} - -// MakeConsumerGenesis returns the created consumer genesis state for consumer chain `consumerId`, -// as well as the validator hash of the initial validator set of the consumer chain -func (k Keeper) MakeConsumerGenesis( - ctx sdk.Context, - consumerId string, - initialValidatorUpdates []abci.ValidatorUpdate, -) (gen ccv.ConsumerGenesisState, err error) { - initializationRecord, err := k.GetConsumerInitializationParameters(ctx, consumerId) - if err != nil { - return gen, errorsmod.Wrapf(ccv.ErrInvalidConsumerState, - "getting initialization parameters, consumerId(%s): %s", consumerId, err.Error()) - } - // note that providerFeePoolAddrStr is sent to the consumer during the IBC Channel handshake; - // see HandshakeMetadata in OnChanOpenTry on the provider-side, and OnChanOpenAck on the consumer-side - consumerGenesisParams := ccv.NewParams( - true, - initializationRecord.BlocksPerDistributionTransmission, - initializationRecord.DistributionTransmissionChannel, - "", // providerFeePoolAddrStr, - initializationRecord.CcvTimeoutPeriod, - initializationRecord.TransferTimeoutPeriod, - initializationRecord.ConsumerRedistributionFraction, - initializationRecord.HistoricalEntries, - initializationRecord.UnbondingPeriod, - []string{}, - []string{}, - ccv.DefaultRetryDelayPeriod, - consumerId, - ) - - // create provider client state and consensus state for the consumer to be able - // to create a provider client - - providerUnbondingPeriod, err := k.stakingKeeper.UnbondingTime(ctx) - if err != nil { - return gen, errorsmod.Wrapf(types.ErrNoUnbondingTime, "unbonding time not found: %s", err) - } - height := clienttypes.GetSelfHeight(ctx) - - clientState := k.GetTemplateClient(ctx) - // this is the counter party chain ID for the consumer - clientState.ChainId = ctx.ChainID() - // this is the latest height the client was updated at, i.e., - // the height of the latest consensus state (see below) - clientState.LatestHeight = height - trustPeriod, err := ccv.CalculateTrustPeriod(providerUnbondingPeriod, k.GetTrustingPeriodFraction(ctx)) - if err != nil { - return gen, errorsmod.Wrapf(sdkerrors.ErrInvalidHeight, "error %s calculating trusting_period for: %s", err, height) - } - clientState.TrustingPeriod = trustPeriod - clientState.UnbondingPeriod = providerUnbondingPeriod - - consState, err := k.clientKeeper.GetSelfConsensusState(ctx, height) - if err != nil { - return gen, errorsmod.Wrapf(clienttypes.ErrConsensusStateNotFound, "error %s getting self consensus state for: %s", err, height) - } - - gen = *ccv.NewInitialConsumerGenesisState( - clientState, - consState.(*ibctmtypes.ConsensusState), - initialValidatorUpdates, - consumerGenesisParams, - ) - return gen, nil -} - -// StopAndPrepareForConsumerRemoval sets the phase of the chain to stopped and prepares to get the state of the -// chain removed after unbonding period elapses -func (k Keeper) StopAndPrepareForConsumerRemoval(ctx sdk.Context, consumerId string) error { - // The phase of the chain is immediately set to stopped, albeit its state is removed later (see below). - // Setting the phase here helps in not considering this chain when we look at launched chains (e.g., in `QueueVSCPackets) - k.SetConsumerPhase(ctx, consumerId, types.CONSUMER_PHASE_STOPPED) - - // state of this chain is removed once UnbondingPeriod elapses - unbondingPeriod, err := k.stakingKeeper.UnbondingTime(ctx) - if err != nil { - return err - } - removalTime := ctx.BlockTime().Add(unbondingPeriod) - - if err := k.SetConsumerRemovalTime(ctx, consumerId, removalTime); err != nil { - return fmt.Errorf("cannot set removal time (%s): %s", removalTime.String(), err.Error()) - } - if err := k.AppendConsumerToBeRemoved(ctx, consumerId, removalTime); err != nil { - return errorsmod.Wrapf(ccv.ErrInvalidConsumerState, "cannot set consumer to be removed: %s", err.Error()) - } - - return nil -} - -// BeginBlockRemoveConsumers removes stopped consumer chain for which the removal time has passed -func (k Keeper) BeginBlockRemoveConsumers(ctx sdk.Context) error { - consumerIds, err := k.ConsumeIdsFromTimeQueue( - ctx, - types.RemovalTimeToConsumerIdsKeyPrefix(), - k.GetConsumersToBeRemoved, - k.DeleteAllConsumersToBeRemoved, - k.AppendConsumerToBeRemoved, - 200, - ) - if err != nil { - return errorsmod.Wrapf(ccv.ErrInvalidConsumerState, "getting consumers ready to stop: %s", err.Error()) - } - for _, consumerId := range consumerIds { - // delete consumer chain in a cached context to abort deletion in case of errors - cachedCtx, writeFn := ctx.CacheContext() - err = k.DeleteConsumerChain(cachedCtx, consumerId) - if err != nil { - k.Logger(ctx).Error("consumer chain could not be removed", - "consumerId", consumerId, - "error", err.Error()) - continue - } - - writeFn() - } - return nil -} - -// DeleteConsumerChain cleans up the state of the given consumer chain -func (k Keeper) DeleteConsumerChain(ctx sdk.Context, consumerId string) (err error) { - phase := k.GetConsumerPhase(ctx, consumerId) - if phase != types.CONSUMER_PHASE_STOPPED { - return fmt.Errorf("cannot delete non-stopped chain: %s", consumerId) - } - - // clean up states - k.DeleteConsumerClientId(ctx, consumerId) - k.DeleteConsumerGenesis(ctx, consumerId) - // Note: this call panics if the key assignment state is invalid - k.DeleteKeyAssignments(ctx, consumerId) - k.DeleteMinimumPowerInTopN(ctx, consumerId) - k.DeleteEquivocationEvidenceMinHeight(ctx, consumerId) - - // close channel and delete the mappings between chain ID and channel ID - if channelID, found := k.GetConsumerIdToChannelId(ctx, consumerId); found { - // Close the channel for the given channel ID on the condition - // that the channel exists and isn't already in the CLOSED state - channel, found := k.channelKeeper.GetChannel(ctx, ccv.ProviderPortID, channelID) - if found && channel.State != channeltypes.CLOSED { - err := k.chanCloseInit(ctx, channelID) - if err != nil { - k.Logger(ctx).Error("channel to consumer chain could not be closed", - "consumerId", consumerId, - "channelID", channelID, - "error", err.Error(), - ) - } - } - k.DeleteConsumerIdToChannelId(ctx, consumerId) - k.DeleteChannelIdToConsumerId(ctx, channelID) - } - - // delete consumer commission rate - provAddrs := k.GetAllCommissionRateValidators(ctx, consumerId) - for _, addr := range provAddrs { - k.DeleteConsumerCommissionRate(ctx, consumerId, addr) - } - - k.DeleteInitChainHeight(ctx, consumerId) - k.DeleteSlashAcks(ctx, consumerId) - k.DeletePendingVSCPackets(ctx, consumerId) - - k.DeleteAllowlist(ctx, consumerId) - k.DeleteDenylist(ctx, consumerId) - k.DeleteAllOptedIn(ctx, consumerId) - k.DeleteConsumerValSet(ctx, consumerId) - - k.DeleteConsumerRewardsAllocation(ctx, consumerId) - k.DeleteConsumerRemovalTime(ctx, consumerId) - - // TODO (PERMISSIONLESS) add newly-added state to be deleted - - // Note that we do not delete ConsumerIdToChainIdKey and ConsumerIdToPhase, as well - // as consumer metadata, initialization and power-shaping parameters. - // This is to enable block explorers and front ends to show information of - // consumer chains that were removed without needing an archive node. - - k.SetConsumerPhase(ctx, consumerId, types.CONSUMER_PHASE_DELETED) - k.Logger(ctx).Info("consumer chain deleted from provider", "consumerId", consumerId) - - return nil -} - -// -// Setters and Getters -// - -// GetConsumerRemovalTime returns the removal time associated with the to-be-removed chain with consumer id -func (k Keeper) GetConsumerRemovalTime(ctx sdk.Context, consumerId string) (time.Time, error) { - store := ctx.KVStore(k.storeKey) - buf := store.Get(types.ConsumerIdToRemovalTimeKey(consumerId)) - if buf == nil { - return time.Time{}, fmt.Errorf("failed to retrieve removal time for consumer id (%s)", consumerId) - } - var time time.Time - if err := time.UnmarshalBinary(buf); err != nil { - return time, fmt.Errorf("failed to unmarshal removal time for consumer id (%s): %w", consumerId, err) - } - return time, nil -} - -// SetConsumerRemovalTime sets the removal time associated with this consumer id -func (k Keeper) SetConsumerRemovalTime(ctx sdk.Context, consumerId string, removalTime time.Time) error { - store := ctx.KVStore(k.storeKey) - buf, err := removalTime.MarshalBinary() - if err != nil { - return fmt.Errorf("failed to marshal removal time (%+v) for consumer id (%s): %w", removalTime, consumerId, err) - } - store.Set(types.ConsumerIdToRemovalTimeKey(consumerId), buf) - return nil -} - -// DeleteConsumerRemovalTime deletes the removal time associated with this consumer id -func (k Keeper) DeleteConsumerRemovalTime(ctx sdk.Context, consumerId string) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.ConsumerIdToRemovalTimeKey(consumerId)) -} - -// getConsumerIdsBasedOnTime returns all the consumer ids stored under this specific `key(time)` -func (k Keeper) getConsumerIdsBasedOnTime(ctx sdk.Context, key func(time.Time) []byte, time time.Time) (types.ConsumerIds, error) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(key(time)) - if bz == nil { - return types.ConsumerIds{}, nil - } - - var consumerIds types.ConsumerIds - - if err := consumerIds.Unmarshal(bz); err != nil { - return types.ConsumerIds{}, fmt.Errorf("failed to unmarshal consumer ids: %w", err) - } - return consumerIds, nil -} - -// appendConsumerIdOnTime appends the consumer id on all the other consumer ids under `key(time)` -func (k Keeper) appendConsumerIdOnTime(ctx sdk.Context, consumerId string, key func(time.Time) []byte, time time.Time) error { - store := ctx.KVStore(k.storeKey) - - consumers, err := k.getConsumerIdsBasedOnTime(ctx, key, time) - if err != nil { - return err - } - - consumersWithAppend := types.ConsumerIds{ - Ids: append(consumers.Ids, consumerId), - } - - bz, err := consumersWithAppend.Marshal() - if err != nil { - return err - } - - store.Set(key(time), bz) - return nil -} - -// removeConsumerIdFromTime removes consumer id stored under `key(time)` -func (k Keeper) removeConsumerIdFromTime(ctx sdk.Context, consumerId string, key func(time.Time) []byte, time time.Time) error { - store := ctx.KVStore(k.storeKey) - - consumers, err := k.getConsumerIdsBasedOnTime(ctx, key, time) - if err != nil { - return err - } - - if len(consumers.Ids) == 0 { - return fmt.Errorf("no consumer ids found for this time: %s", time.String()) - } - - // find the index of the consumer we want to remove - index := -1 - for i := 0; i < len(consumers.Ids); i++ { - if consumers.Ids[i] == consumerId { - index = i - break - } - } - - if index == -1 { - return fmt.Errorf("failed to find consumer id (%s)", consumerId) - } - - if len(consumers.Ids) == 1 { - store.Delete(key(time)) - return nil - } - - consumersWithRemoval := types.ConsumerIds{ - Ids: append(consumers.Ids[:index], consumers.Ids[index+1:]...), - } - - bz, err := consumersWithRemoval.Marshal() - if err != nil { - return err - } - - store.Set(key(time), bz) - return nil -} - -// GetConsumersToBeLaunched returns all the consumer ids of chains stored under this spawn time -func (k Keeper) GetConsumersToBeLaunched(ctx sdk.Context, spawnTime time.Time) (types.ConsumerIds, error) { - return k.getConsumerIdsBasedOnTime(ctx, types.SpawnTimeToConsumerIdsKey, spawnTime) -} - -// AppendConsumerToBeLaunched appends the provider consumer id for the given spawn time -func (k Keeper) AppendConsumerToBeLaunched(ctx sdk.Context, consumerId string, spawnTime time.Time) error { - return k.appendConsumerIdOnTime(ctx, consumerId, types.SpawnTimeToConsumerIdsKey, spawnTime) -} - -// RemoveConsumerToBeLaunched removes consumer id from if stored for this specific spawn time -func (k Keeper) RemoveConsumerToBeLaunched(ctx sdk.Context, consumerId string, spawnTime time.Time) error { - return k.removeConsumerIdFromTime(ctx, consumerId, types.SpawnTimeToConsumerIdsKey, spawnTime) -} - -// DeleteAllConsumersToBeLaunched deletes all consumer to be launched at this specific spawn time -func (k Keeper) DeleteAllConsumersToBeLaunched(ctx sdk.Context, spawnTime time.Time) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.SpawnTimeToConsumerIdsKey(spawnTime)) -} - -// GetConsumersToBeRemoved returns all the consumer ids of chains stored under this removal time -func (k Keeper) GetConsumersToBeRemoved(ctx sdk.Context, removalTime time.Time) (types.ConsumerIds, error) { - return k.getConsumerIdsBasedOnTime(ctx, types.RemovalTimeToConsumerIdsKey, removalTime) -} - -// AppendConsumerToBeRemoved appends the provider consumer id for the given removal time -func (k Keeper) AppendConsumerToBeRemoved(ctx sdk.Context, consumerId string, removalTime time.Time) error { - return k.appendConsumerIdOnTime(ctx, consumerId, types.RemovalTimeToConsumerIdsKey, removalTime) -} - -// RemoveConsumerToBeRemoved removes consumer id from the given removal time -func (k Keeper) RemoveConsumerToBeRemoved(ctx sdk.Context, consumerId string, removalTime time.Time) error { - return k.removeConsumerIdFromTime(ctx, consumerId, types.RemovalTimeToConsumerIdsKey, removalTime) -} - -// DeleteAllConsumersToBeRemoved deletes all consumer to be removed at this specific removal time -func (k Keeper) DeleteAllConsumersToBeRemoved(ctx sdk.Context, removalTime time.Time) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.RemovalTimeToConsumerIdsKey(removalTime)) -} diff --git a/x/ccv/provider/keeper/consumer_lifecycle_test.go b/x/ccv/provider/keeper/consumer_lifecycle_test.go deleted file mode 100644 index 6b258ae003..0000000000 --- a/x/ccv/provider/keeper/consumer_lifecycle_test.go +++ /dev/null @@ -1,1046 +0,0 @@ -package keeper_test - -import ( - "encoding/json" - "fmt" - "testing" - "time" - - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/ibc-go/v8/testing" - _go "github.com/cosmos/ics23/go" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/require" - - "cosmossdk.io/math" - - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - abci "github.com/cometbft/cometbft/abci/types" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - - cryptotestutil "github.com/cosmos/interchain-security/v6/testutil/crypto" - testkeeper "github.com/cosmos/interchain-security/v6/testutil/keeper" - providerkeeper "github.com/cosmos/interchain-security/v6/x/ccv/provider/keeper" - providertypes "github.com/cosmos/interchain-security/v6/x/ccv/provider/types" - ccvtypes "github.com/cosmos/interchain-security/v6/x/ccv/types" -) - -func TestPrepareConsumerForLaunch(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - spawnTime := time.Now().UTC() - err := providerKeeper.PrepareConsumerForLaunch(ctx, CONSUMER_ID, time.Time{}, spawnTime) - require.NoError(t, err) - - consumers, err := providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Equal(t, providertypes.ConsumerIds{Ids: []string{CONSUMER_ID}}, consumers) - - nextSpawnTime := spawnTime.Add(time.Hour) - err = providerKeeper.PrepareConsumerForLaunch(ctx, CONSUMER_ID, spawnTime, nextSpawnTime) - require.NoError(t, err) - - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Empty(t, consumers) - - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, nextSpawnTime) - require.NoError(t, err) - require.Equal(t, providertypes.ConsumerIds{Ids: []string{CONSUMER_ID}}, consumers) -} - -func TestInitializeConsumer(t *testing.T) { - now := time.Now().UTC() - consumerId := "13" - - testCases := []struct { - name string - spawnTime time.Time - setup func(*providerkeeper.Keeper, sdk.Context, time.Time) - expInitialized bool - }{ - { - name: "valid", - spawnTime: now, - setup: func(pk *providerkeeper.Keeper, ctx sdk.Context, spawnTime time.Time) { - pk.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_REGISTERED) - err := pk.SetConsumerInitializationParameters(ctx, consumerId, - providertypes.ConsumerInitializationParameters{ - SpawnTime: spawnTime, - }) - require.NoError(t, err) - }, - expInitialized: true, - }, - { - name: "invalid: no phase", - spawnTime: now, - setup: func(pk *providerkeeper.Keeper, ctx sdk.Context, spawnTime time.Time) { - }, - expInitialized: false, - }, - { - name: "invalid: wrong phase", - spawnTime: now, - setup: func(pk *providerkeeper.Keeper, ctx sdk.Context, spawnTime time.Time) { - pk.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) - err := pk.SetConsumerInitializationParameters(ctx, consumerId, - providertypes.ConsumerInitializationParameters{ - SpawnTime: spawnTime, - }) - require.NoError(t, err) - }, - expInitialized: false, - }, - { - name: "invalid: no init params", - spawnTime: now, - setup: func(pk *providerkeeper.Keeper, ctx sdk.Context, spawnTime time.Time) { - pk.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_REGISTERED) - }, - expInitialized: false, - }, - { - name: "invalid: zero spawn time", - spawnTime: now, - setup: func(pk *providerkeeper.Keeper, ctx sdk.Context, spawnTime time.Time) { - pk.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_REGISTERED) - err := pk.SetConsumerInitializationParameters(ctx, consumerId, - providertypes.ConsumerInitializationParameters{ - SpawnTime: time.Time{}, - }) - require.NoError(t, err) - }, - expInitialized: false, - }, - } - - for _, tc := range testCases { - pk, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - tc.setup(&pk, ctx, tc.spawnTime) - - spawnTime, initialized := pk.InitializeConsumer(ctx, consumerId) - require.Equal(t, tc.expInitialized, initialized, tc.name) - if initialized { - require.Equal(t, tc.spawnTime, spawnTime, tc.name) - require.Equal(t, providertypes.CONSUMER_PHASE_INITIALIZED, pk.GetConsumerPhase(ctx, consumerId)) - } - } -} - -// TestBeginBlockInit directly tests BeginBlockLaunchConsumers against the spec using helpers defined above. -func TestBeginBlockLaunchConsumers(t *testing.T) { - now := time.Now().UTC() - - keeperParams := testkeeper.NewInMemKeeperParams(t) - providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams) - providerKeeper.SetParams(ctx, providertypes.DefaultParams()) - defer ctrl.Finish() - ctx = ctx.WithBlockTime(now) - - // initialize registration, initialization, and update records - chainIds := []string{"chain0", "chain1", "chain2", "chain3", "chain4"} - - initializationParameters := []providertypes.ConsumerInitializationParameters{ - { - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{}, - BinaryHash: []byte{}, - SpawnTime: now.Add(-time.Hour * 2).UTC(), - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - { - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{}, - BinaryHash: []byte{}, - SpawnTime: now.Add(-time.Hour).UTC(), - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - { - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{}, - BinaryHash: []byte{}, - SpawnTime: now.Add(time.Hour).UTC(), - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - { - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{}, - BinaryHash: []byte{}, - SpawnTime: now.Add(-time.Hour).UTC(), - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - { - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{}, - BinaryHash: []byte{}, - SpawnTime: now.Add(-time.Minute).UTC(), - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - } - powerShapingParameters := []providertypes.PowerShapingParameters{ - { - Top_N: 50, - ValidatorsPowerCap: 0, - ValidatorSetCap: 0, - Allowlist: []string{}, - Denylist: []string{}, - }, - { - Top_N: 50, - ValidatorsPowerCap: 0, - ValidatorSetCap: 0, - Allowlist: []string{}, - Denylist: []string{}, - }, - { - Top_N: 50, - ValidatorsPowerCap: 0, - ValidatorSetCap: 0, - Allowlist: []string{}, - Denylist: []string{}, - }, - { - Top_N: 0, - ValidatorsPowerCap: 0, - ValidatorSetCap: 0, - Allowlist: []string{}, - Denylist: []string{}, - }, - { - Top_N: 0, - ValidatorsPowerCap: 0, - ValidatorSetCap: 0, - Allowlist: []string{}, - Denylist: []string{}, - }, - } - - // set up all the records - for i, chainId := range chainIds { - providerKeeper.SetConsumerChainId(ctx, fmt.Sprintf("%d", i), chainId) - } - - for i, r := range initializationParameters { - err := providerKeeper.SetConsumerInitializationParameters(ctx, fmt.Sprintf("%d", i), r) - require.NoError(t, err) - // set up the chains in their initialized phase, hence they could launch - providerKeeper.SetConsumerPhase(ctx, fmt.Sprintf("%d", i), providertypes.CONSUMER_PHASE_INITIALIZED) - err = providerKeeper.AppendConsumerToBeLaunched(ctx, fmt.Sprintf("%d", i), r.SpawnTime) - require.NoError(t, err) - } - for i, r := range powerShapingParameters { - err := providerKeeper.SetConsumerPowerShapingParameters(ctx, fmt.Sprintf("%d", i), r) - require.NoError(t, err) - } - - // opt in a sample validator so the chain's proposal can successfully execute - validator := cryptotestutil.NewCryptoIdentityFromIntSeed(0).SDKStakingValidator() - consAddr, _ := validator.GetConsAddr() - testkeeper.SetupMocksForLastBondedValidatorsExpectation(mocks.MockStakingKeeper, 1, []stakingtypes.Validator{validator}, -1) // -1 to allow any number of calls - - valAddr, _ := sdk.ValAddressFromBech32(validator.GetOperator()) - mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower(gomock.Any(), valAddr).Return(int64(1), nil).AnyTimes() - - providerKeeper.SetOptedIn(ctx, "3", providertypes.NewProviderConsAddress(consAddr)) - - // Expect genesis and client creation for only the first, second, and fifth chains (spawn time already passed and valid) - expectedCalls := testkeeper.GetMocksForMakeConsumerGenesis(ctx, &mocks, time.Hour) - expectedCalls = append(expectedCalls, testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain0", clienttypes.NewHeight(3, 4))...) - expectedCalls = append(expectedCalls, testkeeper.GetMocksForMakeConsumerGenesis(ctx, &mocks, time.Hour)...) - expectedCalls = append(expectedCalls, testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain1", clienttypes.NewHeight(3, 4))...) - expectedCalls = append(expectedCalls, testkeeper.GetMocksForMakeConsumerGenesis(ctx, &mocks, time.Hour)...) - expectedCalls = append(expectedCalls, testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, "chain3", clienttypes.NewHeight(3, 4))...) - - gomock.InOrder(expectedCalls...) - - err := providerKeeper.BeginBlockLaunchConsumers(ctx) - require.NoError(t, err) - - // first chain was successfully launched - phase := providerKeeper.GetConsumerPhase(ctx, "0") - require.Equal(t, providertypes.CONSUMER_PHASE_LAUNCHED, phase) - _, found := providerKeeper.GetConsumerGenesis(ctx, "0") - require.True(t, found) - - // second chain was successfully launched - phase = providerKeeper.GetConsumerPhase(ctx, "1") - require.Equal(t, providertypes.CONSUMER_PHASE_LAUNCHED, phase) - _, found = providerKeeper.GetConsumerGenesis(ctx, "1") - require.True(t, found) - - // third chain was not launched because its spawn time has not passed - phase = providerKeeper.GetConsumerPhase(ctx, "2") - require.Equal(t, providertypes.CONSUMER_PHASE_INITIALIZED, phase) - _, found = providerKeeper.GetConsumerGenesis(ctx, "2") - require.False(t, found) - - // fourth chain corresponds to an Opt-In chain with one opted-in validator and hence the chain gets - // successfully executed - phase = providerKeeper.GetConsumerPhase(ctx, "3") - require.Equal(t, providertypes.CONSUMER_PHASE_LAUNCHED, phase) - _, found = providerKeeper.GetConsumerGenesis(ctx, "3") - require.True(t, found) - - // fifth chain corresponds to an Opt-In chain with no opted-in validators and hence the - // chain launch is NOT successful - phase = providerKeeper.GetConsumerPhase(ctx, "4") - require.Equal(t, providertypes.CONSUMER_PHASE_REGISTERED, phase) - _, found = providerKeeper.GetConsumerGenesis(ctx, "4") - require.False(t, found) -} - -func TestConsumeIdsFromTimeQueue(t *testing.T) { - expectedConsumerIds := []string{"1", "2", "3", "4"} - timestamps := []time.Time{time.Unix(10, 0), time.Unix(20, 0), time.Unix(30, 0)} - - testCases := []struct { - name string - ts time.Time - limit int - expOutcome func(sdk.Context, []string, func(sdk.Context, time.Time) (providertypes.ConsumerIds, error)) - }{ - { - name: "timestamp too early", - ts: time.Unix(9, 999999999), - limit: 3, - expOutcome: func(ctx sdk.Context, ids []string, getIds func(sdk.Context, time.Time) (providertypes.ConsumerIds, error)) { - require.Empty(t, ids) - }, - }, - { - name: "first timestamp", - ts: timestamps[0], - limit: 2, - expOutcome: func(ctx sdk.Context, ids []string, getIds func(sdk.Context, time.Time) (providertypes.ConsumerIds, error)) { - require.Equal(t, expectedConsumerIds[0:2], ids) - - // check that all consumers where removed - consumerIds, err := getIds(ctx, timestamps[0]) - require.NoError(t, err) - require.Empty(t, consumerIds) - }, - }, - { - name: "first timestamp, with limit", - ts: timestamps[0], - limit: 1, - expOutcome: func(ctx sdk.Context, ids []string, getIds func(sdk.Context, time.Time) (providertypes.ConsumerIds, error)) { - require.Equal(t, expectedConsumerIds[0:1], ids) - - // second consumer remained - ret, err := getIds(ctx, timestamps[0]) - require.NoError(t, err) - require.Equal(t, providertypes.ConsumerIds{ - Ids: []string{expectedConsumerIds[1]}, - }, ret) - }, - }, - { - name: "second timestamp", - ts: timestamps[1], - limit: 3, - expOutcome: func(ctx sdk.Context, ids []string, getIds func(sdk.Context, time.Time) (providertypes.ConsumerIds, error)) { - require.Equal(t, expectedConsumerIds[0:3], ids) - - // check that all consumers where removed - ret, err := getIds(ctx, timestamps[0]) - require.NoError(t, err) - require.Empty(t, ret) - ret, err = getIds(ctx, timestamps[1]) - require.NoError(t, err) - require.Empty(t, ret) - }, - }, - { - name: "third timestamp, with limit", - ts: timestamps[1], - limit: 3, - expOutcome: func(ctx sdk.Context, ids []string, getIds func(sdk.Context, time.Time) (providertypes.ConsumerIds, error)) { - require.Equal(t, expectedConsumerIds[0:3], ids) - - // 4th consumer remained - ret, err := getIds(ctx, timestamps[0]) - require.NoError(t, err) - require.Empty(t, ret) - ret, err = getIds(ctx, timestamps[1]) - require.NoError(t, err) - require.Empty(t, ret) - ret, err = getIds(ctx, timestamps[2]) - require.NoError(t, err) - require.Equal(t, providertypes.ConsumerIds{ - Ids: []string{expectedConsumerIds[3]}, - }, ret) - }, - }, - } - - // test for consumers to be launched - for _, tc := range testCases { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - callCases := []struct { - timeQueueKeyPrefix byte - getIds func(sdk.Context, time.Time) (providertypes.ConsumerIds, error) - deleteAllIds func(sdk.Context, time.Time) - appendId func(sdk.Context, string, time.Time) error - }{ - { - timeQueueKeyPrefix: providertypes.SpawnTimeToConsumerIdsKeyPrefix(), - getIds: providerKeeper.GetConsumersToBeLaunched, - deleteAllIds: providerKeeper.DeleteAllConsumersToBeLaunched, - appendId: providerKeeper.AppendConsumerToBeLaunched, - }, - { - timeQueueKeyPrefix: providertypes.RemovalTimeToConsumerIdsKeyPrefix(), - getIds: providerKeeper.GetConsumersToBeRemoved, - deleteAllIds: providerKeeper.DeleteAllConsumersToBeRemoved, - appendId: providerKeeper.AppendConsumerToBeRemoved, - }, - } - for _, cc := range callCases { - err := cc.appendId(ctx, expectedConsumerIds[0], timestamps[0]) - require.NoError(t, err) - err = cc.appendId(ctx, expectedConsumerIds[1], timestamps[0]) - require.NoError(t, err) - err = cc.appendId(ctx, expectedConsumerIds[2], timestamps[1]) - require.NoError(t, err) - err = cc.appendId(ctx, expectedConsumerIds[3], timestamps[2]) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(tc.ts) - - consumerIds, err := providerKeeper.ConsumeIdsFromTimeQueue( - ctx, - cc.timeQueueKeyPrefix, - cc.getIds, - cc.deleteAllIds, - cc.appendId, - tc.limit, - ) - require.NoError(t, err) - - tc.expOutcome(ctx, consumerIds, cc.getIds) - } - } -} - -func TestCreateConsumerClient(t *testing.T) { - type testCase struct { - description string - // Any state-mutating setup on keeper and expected mock calls, specific to this test case - setup func(*providerkeeper.Keeper, sdk.Context, *testkeeper.MockedKeepers) - // Whether a client should be created - expClientCreated bool - } - tests := []testCase{ - { - description: "No state mutation, new client should be created", - setup: func(providerKeeper *providerkeeper.Keeper, ctx sdk.Context, mocks *testkeeper.MockedKeepers) { - providerKeeper.SetConsumerPhase(ctx, CONSUMER_ID, providertypes.CONSUMER_PHASE_INITIALIZED) - - // Valid client creation is asserted with mock expectations here - gomock.InOrder( - testkeeper.GetMocksForCreateConsumerClient(ctx, mocks, CONSUMER_CHAIN_ID, clienttypes.NewHeight(4, 5))..., - ) - }, - expClientCreated: true, - }, - { - description: "chain for this consumer id has already launched, and hence client was created, NO new one is created", - setup: func(providerKeeper *providerkeeper.Keeper, ctx sdk.Context, mocks *testkeeper.MockedKeepers) { - providerKeeper.SetConsumerPhase(ctx, CONSUMER_ID, providertypes.CONSUMER_PHASE_LAUNCHED) - - // Expect none of the client creation related calls to happen - mocks.MockClientKeeper.EXPECT().CreateClient(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) - }, - expClientCreated: false, - }, - } - - for _, tc := range tests { - // Common setup - keeperParams := testkeeper.NewInMemKeeperParams(t) - providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams) - providerKeeper.SetParams(ctx, providertypes.DefaultParams()) - - // Test specific setup - tc.setup(&providerKeeper, ctx, &mocks) - - // Call method with same arbitrary values as defined above in mock expectations. - providerKeeper.SetConsumerChainId(ctx, CONSUMER_ID, CONSUMER_CHAIN_ID) - err := providerKeeper.SetConsumerInitializationParameters(ctx, CONSUMER_ID, testkeeper.GetTestInitializationParameters()) - require.NoError(t, err) - - err = providerKeeper.CreateConsumerClient(ctx, CONSUMER_ID, []byte{}) - if tc.expClientCreated { - require.NoError(t, err) - clientId, found := providerKeeper.GetConsumerClientId(ctx, CONSUMER_ID) - require.True(t, found) - require.Equal(t, "clientID", clientId) - } else { - require.Error(t, err) - } - - // Assert mock calls from setup functions - ctrl.Finish() - } -} - -// TestMakeConsumerGenesis tests the MakeConsumerGenesis keeper method. -// An expected genesis state is hardcoded in json, unmarshaled, and compared -// against an actual consumer genesis state constructed by a provider keeper. -func TestMakeConsumerGenesis(t *testing.T) { - keeperParams := testkeeper.NewInMemKeeperParams(t) - providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams) - defer ctrl.Finish() - - moduleParams := providertypes.Params{ - TemplateClient: &ibctmtypes.ClientState{ - TrustLevel: ibctmtypes.DefaultTrustLevel, - MaxClockDrift: 10000000000, - ProofSpecs: []*_go.ProofSpec{ - { - LeafSpec: &_go.LeafOp{ - Hash: _go.HashOp_SHA256, - PrehashKey: _go.HashOp_NO_HASH, - PrehashValue: _go.HashOp_SHA256, - Length: _go.LengthOp_VAR_PROTO, - Prefix: []byte{0x00}, - }, - InnerSpec: &_go.InnerSpec{ - ChildOrder: []int32{0, 1}, - ChildSize: 33, - MinPrefixLength: 4, - MaxPrefixLength: 12, - Hash: _go.HashOp_SHA256, - }, - MaxDepth: 0, - MinDepth: 0, - }, - { - LeafSpec: &_go.LeafOp{ - Hash: _go.HashOp_SHA256, - PrehashKey: _go.HashOp_NO_HASH, - PrehashValue: _go.HashOp_SHA256, - Length: _go.LengthOp_VAR_PROTO, - Prefix: []byte{0x00}, - }, - InnerSpec: &_go.InnerSpec{ - ChildOrder: []int32{0, 1}, - ChildSize: 32, - MinPrefixLength: 1, - MaxPrefixLength: 1, - Hash: _go.HashOp_SHA256, - }, - MaxDepth: 0, - }, - }, - UpgradePath: []string{"upgrade", "upgradedIBCState"}, - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: true, - }, - // Note these are unused provider parameters for this test, and not actually asserted against - // They must be populated with reasonable values to satisfy SetParams though. - TrustingPeriodFraction: providertypes.DefaultTrustingPeriodFraction, - CcvTimeoutPeriod: ccvtypes.DefaultCCVTimeoutPeriod, - SlashMeterReplenishPeriod: providertypes.DefaultSlashMeterReplenishPeriod, - SlashMeterReplenishFraction: providertypes.DefaultSlashMeterReplenishFraction, - ConsumerRewardDenomRegistrationFee: sdk.Coin{ - Denom: "stake", - Amount: math.NewInt(1000000), - }, - BlocksPerEpoch: 600, - NumberOfEpochsToStartReceivingRewards: 24, - } - providerKeeper.SetParams(ctx, moduleParams) - - // matches params from jsonString - ccvTimeoutPeriod := time.Duration(2419200000000000) - transferTimeoutPeriod := time.Duration(3600000000000) - consumerUnbondingPeriod := time.Duration(1728000000000000) - providerUnbondingPeriod := time.Duration(1814400000000000) - trustingPeriod := time.Duration(1197504000000000) - providerChainId := "provider-1" - providerRevisionNumber := uint64(1) - providerRevisionHeight := int64(5) - - initializationParameters := providertypes.ConsumerInitializationParameters{ - BlocksPerDistributionTransmission: 1000, - CcvTimeoutPeriod: ccvTimeoutPeriod, - TransferTimeoutPeriod: transferTimeoutPeriod, - ConsumerRedistributionFraction: "0.75", - HistoricalEntries: 10000, - UnbondingPeriod: consumerUnbondingPeriod, - } - - // - // Other setup not covered by custom template client state - // - ctx = ctx.WithChainID(providerChainId) // consumerId is obtained from ctx - ctx = ctx.WithBlockHeight(providerRevisionHeight) // RevisionHeight obtained from ctx - gomock.InOrder(testkeeper.GetMocksForMakeConsumerGenesis(ctx, &mocks, providerUnbondingPeriod)...) - - providerKeeper.SetConsumerChainId(ctx, CONSUMER_ID, CONSUMER_CHAIN_ID) - err := providerKeeper.SetConsumerInitializationParameters(ctx, CONSUMER_ID, initializationParameters) - require.NoError(t, err) - - _, pks, _ := ibctesting.GenerateKeys(t, 2) - var ppks [2]tmprotocrypto.PublicKey - for i, pk := range pks { - ppks[i], _ = cryptocodec.ToCmtProtoPublicKey(pk) - } - initialValUpdates := []abci.ValidatorUpdate{ - {PubKey: ppks[0], Power: 1}, - {PubKey: ppks[1], Power: 2}, - } - - actualGenesis, err := providerKeeper.MakeConsumerGenesis(ctx, CONSUMER_ID, initialValUpdates) - require.NoError(t, err) - - // JSON string with tabs, newlines and spaces for readability - jsonString := fmt.Sprintf(`{ - "params": { - "enabled": true, - "blocks_per_distribution_transmission": %d, - "ccv_timeout_period": %d, - "transfer_timeout_period": %d, - "consumer_redistribution_fraction": "%s", - "historical_entries": %d, - "unbonding_period": %d, - "soft_opt_out_threshold": "0", - "reward_denoms": [], - "provider_reward_denoms": [], - "retry_delay_period": %d, - "consumer_id": "%s" - }, - "new_chain": true, - "provider" : { - "client_state": { - "chain_id": "%s", - "trust_level": { - "numerator": 1, - "denominator": 3 - }, - "trusting_period": %d, - "unbonding_period": %d, - "max_clock_drift": %d, - "frozen_height": {}, - "latest_height": { - "revision_number": %d, - "revision_height": %d - }, - "proof_specs": [ - { - "leaf_spec": { - "hash": 1, - "prehash_value": 1, - "length": 1, - "prefix": "AA==" - }, - "inner_spec": { - "child_order": [0, 1], - "child_size": 33, - "min_prefix_length": 4, - "max_prefix_length": 12, - "hash": 1 - } - }, - { - "leaf_spec": { - "hash": 1, - "prehash_value": 1, - "length": 1, - "prefix": "AA==" - }, - "inner_spec": { - "child_order": [0, 1], - "child_size": 32, - "min_prefix_length": 1, - "max_prefix_length": 1, - "hash": 1 - } - } - ], - "upgrade_path": ["upgrade", "upgradedIBCState"], - "allow_update_after_expiry": true, - "allow_update_after_misbehaviour": true - }, - "consensus_state": { - "timestamp": "2020-01-02T00:00:10Z", - "root": { - "hash": "LpGpeyQVLUo9HpdsgJr12NP2eCICspcULiWa5u9udOA=" - }, - "next_validators_hash": "E30CE736441FB9101FADDAF7E578ABBE6DFDB67207112350A9A904D554E1F5BE" - }, - "initial_val_set": [{}] - } - }`, - initializationParameters.BlocksPerDistributionTransmission, - ccvTimeoutPeriod.Nanoseconds(), - transferTimeoutPeriod.Nanoseconds(), - initializationParameters.ConsumerRedistributionFraction, - initializationParameters.HistoricalEntries, - consumerUnbondingPeriod.Nanoseconds(), - ccvtypes.DefaultRetryDelayPeriod.Nanoseconds(), - CONSUMER_ID, - providerChainId, - trustingPeriod.Nanoseconds(), - providerUnbondingPeriod.Nanoseconds(), - providertypes.DefaultMaxClockDrift.Nanoseconds(), - providerRevisionNumber, - providerRevisionHeight, - ) - - var expectedGenesis ccvtypes.ConsumerGenesisState - err = json.Unmarshal([]byte(jsonString), &expectedGenesis) // ignores tabs, newlines and spaces - require.NoError(t, err) - expectedGenesis.Provider.InitialValSet = initialValUpdates - - // Zeroing out different fields that are challenging to mock - actualGenesis.Provider.ConsensusState = &ibctmtypes.ConsensusState{} - expectedGenesis.Provider.ConsensusState = &ibctmtypes.ConsensusState{} - - require.Equal(t, expectedGenesis, actualGenesis, "consumer chain genesis created incorrectly") -} - -func TestBeginBlockStopConsumers(t *testing.T) { - now := time.Now().UTC() - - keeperParams := testkeeper.NewInMemKeeperParams(t) - providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams) - providerKeeper.SetParams(ctx, providertypes.DefaultParams()) - defer ctrl.Finish() - ctx = ctx.WithBlockTime(now) - - chainIds := []string{"chain1", "chain2", "chain3"} - consumerIds := []string{"consumerId1", "consumerId2", "consumerId3"} - err := providerKeeper.SetConsumerRemovalTime(ctx, consumerIds[0], now.Add(-time.Hour)) - require.NoError(t, err) - err = providerKeeper.AppendConsumerToBeRemoved(ctx, consumerIds[0], now.Add(-time.Hour)) - require.NoError(t, err) - err = providerKeeper.SetConsumerRemovalTime(ctx, consumerIds[1], now) - require.NoError(t, err) - err = providerKeeper.AppendConsumerToBeRemoved(ctx, consumerIds[1], now) - require.NoError(t, err) - err = providerKeeper.SetConsumerRemovalTime(ctx, consumerIds[2], now.Add(time.Hour)) - require.NoError(t, err) - err = providerKeeper.AppendConsumerToBeRemoved(ctx, consumerIds[2], now.Add(time.Hour)) - require.NoError(t, err) - - // - // Mock expectations - // - expectations := []*gomock.Call{} - for i := range consumerIds { - chainId := chainIds[i] - // A consumer chain is setup corresponding to each consumerId, making these mocks necessary - expectations = append(expectations, testkeeper.GetMocksForCreateConsumerClient(ctx, &mocks, - chainId, clienttypes.NewHeight(2, 3))...) - expectations = append(expectations, testkeeper.GetMocksForSetConsumerChain(ctx, &mocks, chainId)...) - } - // Only first two consumer chains should be stopped - expectations = append(expectations, testkeeper.GetMocksForDeleteConsumerChain(ctx, &mocks)...) - expectations = append(expectations, testkeeper.GetMocksForDeleteConsumerChain(ctx, &mocks)...) - - gomock.InOrder(expectations...) - - // - // Remaining setup - // - for i, consumerId := range consumerIds { - // Setup a valid consumer chain for each consumerId - initializationRecord := testkeeper.GetTestInitializationParameters() - initializationRecord.InitialHeight = clienttypes.NewHeight(2, 3) - registrationRecord := testkeeper.GetTestConsumerMetadata() - - providerKeeper.SetConsumerChainId(ctx, consumerId, chainIds[i]) - err = providerKeeper.SetConsumerMetadata(ctx, consumerId, registrationRecord) - require.NoError(t, err) - err = providerKeeper.SetConsumerInitializationParameters(ctx, consumerId, initializationRecord) - require.NoError(t, err) - err = providerKeeper.SetConsumerPowerShapingParameters(ctx, consumerId, testkeeper.GetTestPowerShapingParameters()) - require.NoError(t, err) - providerKeeper.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_INITIALIZED) - providerKeeper.SetConsumerClientId(ctx, consumerId, "clientID") - - err = providerKeeper.CreateConsumerClient(ctx, consumerId, []byte{}) - require.NoError(t, err) - err = providerKeeper.SetConsumerChain(ctx, "channelID") - require.NoError(t, err) - - // the chain is considered to be stopped and ready for deletion (i.e., `StopAndPrepareForConsumerRemoval` is called) - providerKeeper.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_STOPPED) - } - - // - // Test execution - // - - err = providerKeeper.BeginBlockRemoveConsumers(ctx) - require.NoError(t, err) - - // Only the 3rd (final) proposal is still stored as pending - phase := providerKeeper.GetConsumerPhase(ctx, consumerIds[0]) - require.Equal(t, providertypes.CONSUMER_PHASE_DELETED, phase) - phase = providerKeeper.GetConsumerPhase(ctx, consumerIds[1]) - require.Equal(t, providertypes.CONSUMER_PHASE_DELETED, phase) - // third chain had a removal time in the future and hence did not get deleted - phase = providerKeeper.GetConsumerPhase(ctx, consumerIds[2]) - require.Equal(t, providertypes.CONSUMER_PHASE_STOPPED, phase) -} - -// Tests the DeleteConsumerChain method against the spec, -// with more granularity than what's covered in TestHandleLegacyConsumerRemovalProposal, or integration tests. -// See: https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/methods.md#ccv-pcf-stcc1 -// Spec tag: [CCV-PCF-STCC.1] -func TestStopConsumerChain(t *testing.T) { - type testCase struct { - description string - // State-mutating setup specific to this test case - setup func(sdk.Context, *providerkeeper.Keeper, testkeeper.MockedKeepers) - // Whether we should expect the method to return an error - expErr bool - } - - consumerId := "0" - - tests := []testCase{ - { - description: "proposal dropped, client doesn't exist", - setup: func(ctx sdk.Context, providerKeeper *providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { - // No mocks, meaning no external keeper methods are allowed to be called. - }, - expErr: true, - }, - { - description: "valid stop of consumer chain, all mock calls hit", - setup: func(ctx sdk.Context, providerKeeper *providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { - testkeeper.SetupForDeleteConsumerChain(t, ctx, providerKeeper, mocks, consumerId) - - // set consumer minimum equivocation height - providerKeeper.SetEquivocationEvidenceMinHeight(ctx, consumerId, 1) - - // assert mocks for expected calls to `DeleteConsumerChain` when closing the underlying channel - gomock.InOrder(testkeeper.GetMocksForDeleteConsumerChain(ctx, &mocks)...) - }, - expErr: false, - }, - } - - for _, tc := range tests { - - // Common setup - keeperParams := testkeeper.NewInMemKeeperParams(t) - providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, keeperParams) - providerKeeper.SetParams(ctx, providertypes.DefaultParams()) - - // Setup specific to test case - tc.setup(ctx, &providerKeeper, mocks) - - err := providerKeeper.DeleteConsumerChain(ctx, consumerId) - - if tc.expErr { - require.Error(t, err, t) - } else { - require.NoError(t, err) - } - - testkeeper.TestProviderStateIsCleanedAfterConsumerChainIsDeleted(t, ctx, providerKeeper, consumerId, "channelID", tc.expErr) - - ctrl.Finish() - } -} - -// -// Setters and Getters -// - -// TestConsumerRemovalTime tests the getter, setter, and deletion of the consumer id to removal times methods -func TestConsumerRemovalTime(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - _, err := providerKeeper.GetConsumerRemovalTime(ctx, CONSUMER_ID) - require.Error(t, err) - - expectedRemovalTime := time.Unix(1234, 56789) - providerKeeper.SetConsumerRemovalTime(ctx, CONSUMER_ID, expectedRemovalTime) - actualRemovalTime, err := providerKeeper.GetConsumerRemovalTime(ctx, CONSUMER_ID) - require.NoError(t, err) - require.Equal(t, actualRemovalTime, expectedRemovalTime) - - providerKeeper.DeleteConsumerRemovalTime(ctx, CONSUMER_ID) - _, err = providerKeeper.GetConsumerRemovalTime(ctx, CONSUMER_ID) - require.Error(t, err) -} - -// TestConsumersToBeLaunched tests `AppendConsumerToBeLaunched`, `GetConsumersToBeLaunched`, and `RemoveConsumerToBeLaunched` -func TestConsumersToBeLaunched(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - spawnTime := time.Now() - err := providerKeeper.AppendConsumerToBeLaunched(ctx, "consumerId1", spawnTime) - require.NoError(t, err) - consumers, err := providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1"}, consumers.Ids) - - err = providerKeeper.AppendConsumerToBeLaunched(ctx, "consumerId2", spawnTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1", "consumerId2"}, consumers.Ids) - - err = providerKeeper.AppendConsumerToBeLaunched(ctx, "consumerId3", spawnTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1", "consumerId2", "consumerId3"}, consumers.Ids) - - err = providerKeeper.RemoveConsumerToBeLaunched(ctx, "consumerId2", spawnTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1", "consumerId3"}, consumers.Ids) - - // also add consumer ids under a different spawn time and verify everything under the original spawn time is still there - spawnTimePlusOneHour := spawnTime.Add(time.Hour) - err = providerKeeper.AppendConsumerToBeLaunched(ctx, "consumerId4", spawnTimePlusOneHour) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTimePlusOneHour) - require.NoError(t, err) - require.Equal(t, []string{"consumerId4"}, consumers.Ids) - - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1", "consumerId3"}, consumers.Ids) - - // start removing all consumers from `spawnTime` - err = providerKeeper.RemoveConsumerToBeLaunched(ctx, "consumerId3", spawnTime) - require.NoError(t, err) - err = providerKeeper.RemoveConsumerToBeLaunched(ctx, "consumerId1", spawnTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Empty(t, consumers.Ids) - - // remove from `spawnTimePlusOneHour` - err = providerKeeper.RemoveConsumerToBeLaunched(ctx, "consumerId4", spawnTimePlusOneHour) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTimePlusOneHour) - require.NoError(t, err) - require.Empty(t, consumers.Ids) - - // add another consumer for `spawnTime` - err = providerKeeper.AppendConsumerToBeLaunched(ctx, "consumerId5", spawnTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeLaunched(ctx, spawnTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId5"}, consumers.Ids) -} - -// TestConsumersToBeRemoved tests `AppendConsumerToBeRemoved`, `GetConsumersToBeRemoved`, and `RemoveConsumerToBeRemoved` -func TestConsumersToBeRemoved(t *testing.T) { - providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - removalTime := time.Now() - err := providerKeeper.AppendConsumerToBeRemoved(ctx, "consumerId1", removalTime) - require.NoError(t, err) - consumers, err := providerKeeper.GetConsumersToBeRemoved(ctx, removalTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1"}, consumers.Ids) - - err = providerKeeper.AppendConsumerToBeRemoved(ctx, "consumerId2", removalTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeRemoved(ctx, removalTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1", "consumerId2"}, consumers.Ids) - - err = providerKeeper.AppendConsumerToBeRemoved(ctx, "consumerId3", removalTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeRemoved(ctx, removalTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1", "consumerId2", "consumerId3"}, consumers.Ids) - - err = providerKeeper.RemoveConsumerToBeRemoved(ctx, "consumerId2", removalTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeRemoved(ctx, removalTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1", "consumerId3"}, consumers.Ids) - - // also add consumer ids under a different removal time and verify everything under the original removal time is still there - removalTimePlusOneHour := removalTime.Add(time.Hour) - err = providerKeeper.AppendConsumerToBeRemoved(ctx, "consumerId4", removalTimePlusOneHour) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeRemoved(ctx, removalTimePlusOneHour) - require.NoError(t, err) - require.Equal(t, []string{"consumerId4"}, consumers.Ids) - - consumers, err = providerKeeper.GetConsumersToBeRemoved(ctx, removalTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId1", "consumerId3"}, consumers.Ids) - - // start removing all consumers from `removalTime` - err = providerKeeper.RemoveConsumerToBeRemoved(ctx, "consumerId3", removalTime) - require.NoError(t, err) - err = providerKeeper.RemoveConsumerToBeRemoved(ctx, "consumerId1", removalTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeRemoved(ctx, removalTime) - require.NoError(t, err) - require.Empty(t, consumers.Ids) - - // remove from `removalTimePlusOneHour` - err = providerKeeper.RemoveConsumerToBeRemoved(ctx, "consumerId4", removalTimePlusOneHour) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeRemoved(ctx, removalTimePlusOneHour) - require.NoError(t, err) - require.Empty(t, consumers.Ids) - - // add another consumer for `removalTime` - err = providerKeeper.AppendConsumerToBeRemoved(ctx, "consumerId5", removalTime) - require.NoError(t, err) - consumers, err = providerKeeper.GetConsumersToBeRemoved(ctx, removalTime) - require.NoError(t, err) - require.Equal(t, []string{"consumerId5"}, consumers.Ids) -} diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index 6fc0c16afd..d2a36c686d 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -24,14 +24,8 @@ func (k Keeper) QueryConsumerGenesis(c context.Context, req *types.QueryConsumer return nil, status.Errorf(codes.InvalidArgument, "empty request") } -<<<<<<< HEAD if req.ChainId == "" { return nil, status.Errorf(codes.InvalidArgument, "invalid request: chain id cannot be empty") -======= - consumerId := req.ConsumerId - if err := ccvtypes.ValidateConsumerId(consumerId); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) } gen, ok := k.GetConsumerGenesis(ctx, req.ChainId) @@ -152,14 +146,6 @@ func (k Keeper) QueryValidatorConsumerAddr(goCtx context.Context, req *types.Que ctx := sdk.UnwrapSDKContext(goCtx) -<<<<<<< HEAD -======= - consumerId := req.ConsumerId - if err := ccvtypes.ValidateConsumerId(consumerId); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) providerAddrTmp, err := sdk.ConsAddressFromBech32(req.ProviderAddress) if err != nil { return nil, err @@ -241,7 +227,6 @@ func (k Keeper) QueryProposedConsumerChainIDs(goCtx context.Context, req *types. return nil, status.Error(codes.InvalidArgument, "empty request") } -<<<<<<< HEAD ctx := sdk.UnwrapSDKContext(goCtx) chains := k.GetAllProposedConsumerChainIDs(ctx) @@ -258,11 +243,6 @@ func (k Keeper) QueryAllPairsValConAddrByConsumerChainID(goCtx context.Context, if req.ChainId == "" { return nil, status.Error(codes.InvalidArgument, "empty chainId") -======= - consumerId := req.ConsumerId - if err := ccvtypes.ValidateConsumerId(consumerId); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) } // list of pairs valconsensus addr @@ -305,15 +285,9 @@ func (k Keeper) QueryConsumerChainOptedInValidators(goCtx context.Context, req * return nil, status.Error(codes.InvalidArgument, "empty request") } -<<<<<<< HEAD consumerChainID := req.ChainId if consumerChainID == "" { return nil, status.Error(codes.InvalidArgument, "empty chainId") -======= - consumerId := req.ConsumerId - if err := ccvtypes.ValidateConsumerId(consumerId); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) } optedInVals := []string{} @@ -338,15 +312,9 @@ func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryC return nil, status.Error(codes.InvalidArgument, "empty request") } -<<<<<<< HEAD consumerChainID := req.ChainId if consumerChainID == "" { return nil, status.Error(codes.InvalidArgument, "empty chainId") -======= - consumerId := req.ConsumerId - if err := ccvtypes.ValidateConsumerId(consumerId); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) } ctx := sdk.UnwrapSDKContext(goCtx) @@ -456,15 +424,9 @@ func (k Keeper) QueryValidatorConsumerCommissionRate(goCtx context.Context, req return nil, status.Error(codes.InvalidArgument, "empty request") } -<<<<<<< HEAD consumerChainID := req.ChainId if consumerChainID == "" { return nil, status.Error(codes.InvalidArgument, "empty chainId") -======= - consumerId := req.ConsumerId - if err := ccvtypes.ValidateConsumerId(consumerId); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) } consAddr, err := sdk.ConsAddressFromBech32(req.ProviderAddress) @@ -503,20 +465,8 @@ func (k Keeper) QueryOldestUnconfirmedVsc(goCtx context.Context, req *types.Quer return nil, status.Errorf(codes.InvalidArgument, "empty request") } -<<<<<<< HEAD if req.ChainId == "" { return nil, status.Errorf(codes.InvalidArgument, "invalid request: chain id cannot be empty") -======= - consumerId := req.ConsumerId - if err := ccvtypes.ValidateConsumerId(consumerId); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - ctx := sdk.UnwrapSDKContext(goCtx) - - chainId, err := k.GetConsumerChainId(ctx, consumerId) - if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "cannot retrieve chain id for consumer id: %s", consumerId) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) } if _, consumerRegistered := k.GetConsumerClientId(ctx, req.ChainId); !consumerRegistered { diff --git a/x/ccv/provider/types/errors.go b/x/ccv/provider/types/errors.go index 11e287dade..5109489d76 100644 --- a/x/ccv/provider/types/errors.go +++ b/x/ccv/provider/types/errors.go @@ -6,7 +6,6 @@ import ( // Provider sentinel errors var ( -<<<<<<< HEAD ErrInvalidConsumerAdditionProposal = errorsmod.Register(ModuleName, 1, "invalid consumer addition proposal") ErrInvalidConsumerRemovalProp = errorsmod.Register(ModuleName, 2, "invalid consumer removal proposal") ErrUnknownConsumerChainId = errorsmod.Register(ModuleName, 3, "no consumer chain with this chain id") @@ -33,39 +32,4 @@ var ( ErrInvalidAddress = errorsmod.Register(ModuleName, 24, "invalid address") ErrUnauthorized = errorsmod.Register(ModuleName, 25, "unauthorized") ErrBlankConsumerChainID = errorsmod.Register(ModuleName, 26, "consumer chain id must not be blank") -======= - ErrUnknownConsumerId = errorsmod.Register(ModuleName, 3, "no consumer chain with this consumer id") - ErrUnknownConsumerChannelId = errorsmod.Register(ModuleName, 4, "no consumer chain with this channel id") - ErrConsumerKeyInUse = errorsmod.Register(ModuleName, 10, "consumer key is already in use by a validator") - ErrCannotAssignDefaultKeyAssignment = errorsmod.Register(ModuleName, 11, "cannot re-assign default key assignment") - ErrInvalidConsumerRewardDenom = errorsmod.Register(ModuleName, 14, "invalid consumer reward denom") - ErrInvalidConsumerClient = errorsmod.Register(ModuleName, 16, "ccv channel is not built on correct client") - ErrCannotOptOutFromTopN = errorsmod.Register(ModuleName, 20, "cannot opt out from a Top N chain") - ErrNoUnbondingTime = errorsmod.Register(ModuleName, 23, "provider unbonding time not found") - ErrUnauthorized = errorsmod.Register(ModuleName, 25, "unauthorized") - ErrInvalidPhase = errorsmod.Register(ModuleName, 27, "cannot perform action in the current phase of consumer chain") - ErrInvalidConsumerMetadata = errorsmod.Register(ModuleName, 28, "invalid consumer metadata") - ErrInvalidPowerShapingParameters = errorsmod.Register(ModuleName, 29, "invalid power shaping parameters") - ErrInvalidConsumerInitializationParameters = errorsmod.Register(ModuleName, 30, "invalid consumer initialization parameters") - ErrCannotUpdateMinimumPowerInTopN = errorsmod.Register(ModuleName, 31, "cannot update minimum power in Top N") - ErrNoConsumerGenesis = errorsmod.Register(ModuleName, 33, "missing consumer genesis") - ErrInvalidConsumerGenesis = errorsmod.Register(ModuleName, 34, "invalid consumer genesis") - ErrNoConsumerId = errorsmod.Register(ModuleName, 35, "missing consumer id") - ErrAlreadyOptedIn = errorsmod.Register(ModuleName, 36, "already opted in to a chain with the same chain id") - ErrNoOwnerAddress = errorsmod.Register(ModuleName, 37, "missing owner address") - ErrInvalidNewOwnerAddress = errorsmod.Register(ModuleName, 38, "invalid new owner address") - ErrInvalidTransformToTopN = errorsmod.Register(ModuleName, 39, "invalid transform to Top N chain") - ErrInvalidTransformToOptIn = errorsmod.Register(ModuleName, 40, "invalid transform to Opt In chain") - ErrCannotCreateTopNChain = errorsmod.Register(ModuleName, 41, "cannot create Top N chain outside permissionlessly") - ErrInvalidRemovalTime = errorsmod.Register(ModuleName, 43, "invalid removal time") - ErrInvalidMsgCreateConsumer = errorsmod.Register(ModuleName, 44, "invalid create consumer message") - ErrInvalidMsgUpdateConsumer = errorsmod.Register(ModuleName, 45, "invalid update consumer message") - ErrInvalidMsgAssignConsumerKey = errorsmod.Register(ModuleName, 46, "invalid assign consumer key message") - ErrInvalidMsgSubmitConsumerMisbehaviour = errorsmod.Register(ModuleName, 47, "invalid submit consumer misbehaviour message") - ErrInvalidMsgSubmitConsumerDoubleVoting = errorsmod.Register(ModuleName, 48, "invalid submit consumer double voting message") - ErrInvalidMsgOptIn = errorsmod.Register(ModuleName, 49, "invalid opt in message") - ErrInvalidMsgOptOut = errorsmod.Register(ModuleName, 50, "invalid opt out message") - ErrInvalidMsgSetConsumerCommissionRate = errorsmod.Register(ModuleName, 51, "invalid set consumer commission rate message") - ErrInvalidMsgChangeRewardDenoms = errorsmod.Register(ModuleName, 52, "invalid change reward denoms message") ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) ) diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index f3a1164ecc..59545dc1bb 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -97,17 +97,11 @@ func (msg MsgAssignConsumerKey) ValidateBasic() error { if strings.TrimSpace(msg.ChainId) == "" { return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot be blank") } -<<<<<<< HEAD // It is possible to assign keys for consumer chains that are not yet approved. // This can only be done by a signing validator, but it is still sensible // to limit the chainID size to prevent abuse. if 128 < len(msg.ChainId) { return errorsmod.Wrapf(ErrInvalidConsumerChainID, "chainId cannot exceed 128 length") -======= - - if err := ccvtypes.ValidateConsumerId(msg.ConsumerId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgAssignConsumerKey, "ConsumerId: %s", err.Error()) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) } valAddr, err := sdk.ValAddressFromBech32(msg.ProviderAddr) if err != nil { @@ -121,319 +115,11 @@ func (msg MsgAssignConsumerKey) ValidateBasic() error { return ErrInvalidConsumerConsensusPubKey } if _, _, err := ParseConsumerKeyFromJson(msg.ConsumerKey); err != nil { -<<<<<<< HEAD return ErrInvalidConsumerConsensusPubKey -======= - return errorsmod.Wrapf(ErrInvalidMsgAssignConsumerKey, "ConsumerKey: %s", err.Error()) - } - - return nil -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg *MsgChangeRewardDenoms) ValidateBasic() error { - emptyDenomsToAdd := len(msg.DenomsToAdd) == 0 - emptyDenomsToRemove := len(msg.DenomsToRemove) == 0 - // Return error if both sets are empty or nil - if emptyDenomsToAdd && emptyDenomsToRemove { - return errorsmod.Wrapf(ErrInvalidMsgChangeRewardDenoms, "both DenomsToAdd and DenomsToRemove are empty") - } - - denomMap := map[string]struct{}{} - for _, denom := range msg.DenomsToAdd { - // validate the denom - if !sdk.NewCoin(denom, math.NewInt(1)).IsValid() { - return errorsmod.Wrapf(ErrInvalidMsgChangeRewardDenoms, "DenomsToAdd: invalid denom(%s)", denom) - } - denomMap[denom] = struct{}{} - } - for _, denom := range msg.DenomsToRemove { - // validate the denom - if !sdk.NewCoin(denom, math.NewInt(1)).IsValid() { - return errorsmod.Wrapf(ErrInvalidMsgChangeRewardDenoms, "DenomsToRemove: invalid denom(%s)", denom) - } - // denom cannot be in both sets - if _, found := denomMap[denom]; found { - return errorsmod.Wrapf(ErrInvalidMsgChangeRewardDenoms, - "denom(%s) cannot be both added and removed", denom) - } - } - - return nil -} - -func NewMsgSubmitConsumerMisbehaviour( - consumerId string, - submitter sdk.AccAddress, - misbehaviour *ibctmtypes.Misbehaviour, -) (*MsgSubmitConsumerMisbehaviour, error) { - return &MsgSubmitConsumerMisbehaviour{ - Submitter: submitter.String(), - Misbehaviour: misbehaviour, - ConsumerId: consumerId, - }, nil -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgSubmitConsumerMisbehaviour) ValidateBasic() error { - if err := ccvtypes.ValidateConsumerId(msg.ConsumerId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSubmitConsumerMisbehaviour, "ConsumerId: %s", err.Error()) - } - - if err := msg.Misbehaviour.ValidateBasic(); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSubmitConsumerMisbehaviour, "Misbehaviour: %s", err.Error()) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) - } - return nil -} - -<<<<<<< HEAD -======= -func NewMsgSubmitConsumerDoubleVoting( - consumerId string, - submitter sdk.AccAddress, - ev *tmtypes.DuplicateVoteEvidence, - header *ibctmtypes.Header, -) (*MsgSubmitConsumerDoubleVoting, error) { - return &MsgSubmitConsumerDoubleVoting{ - Submitter: submitter.String(), - DuplicateVoteEvidence: ev, - InfractionBlockHeader: header, - ConsumerId: consumerId, - }, nil -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgSubmitConsumerDoubleVoting) ValidateBasic() error { - if dve, err := cmttypes.DuplicateVoteEvidenceFromProto(msg.DuplicateVoteEvidence); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSubmitConsumerDoubleVoting, "DuplicateVoteEvidence: %s", err.Error()) - } else { - if err = dve.ValidateBasic(); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSubmitConsumerDoubleVoting, "DuplicateVoteEvidence: %s", err.Error()) - } - } - - if err := ValidateHeaderForConsumerDoubleVoting(msg.InfractionBlockHeader); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSubmitConsumerDoubleVoting, "ValidateTendermintHeader: %s", err.Error()) - } - - if err := ccvtypes.ValidateConsumerId(msg.ConsumerId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSubmitConsumerDoubleVoting, "ConsumerId: %s", err.Error()) - } - - return nil -} - -// NewMsgOptIn creates a new NewMsgOptIn instance. -func NewMsgOptIn(consumerId string, providerValidatorAddress sdk.ValAddress, consumerConsensusPubKey, signer string) (*MsgOptIn, error) { - return &MsgOptIn{ - ConsumerId: consumerId, - ProviderAddr: providerValidatorAddress.String(), - ConsumerKey: consumerConsensusPubKey, - Signer: signer, - }, nil -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgOptIn) ValidateBasic() error { - if err := validateDeprecatedChainId(msg.ChainId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgOptIn, "ChainId: %s", err.Error()) - } - - if err := ccvtypes.ValidateConsumerId(msg.ConsumerId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgOptIn, "ConsumerId: %s", err.Error()) - } - - if err := validateProviderAddress(msg.ProviderAddr, msg.Signer); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgOptIn, "ProviderAddr: %s", err.Error()) - } - - if msg.ConsumerKey != "" { - if _, _, err := ParseConsumerKeyFromJson(msg.ConsumerKey); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgOptIn, "ConsumerKey: %s", err.Error()) - } - } - return nil -} - -// NewMsgOptOut creates a new NewMsgOptIn instance. -func NewMsgOptOut(consumerId string, providerValidatorAddress sdk.ValAddress, signer string) (*MsgOptOut, error) { - return &MsgOptOut{ - ConsumerId: consumerId, - ProviderAddr: providerValidatorAddress.String(), - Signer: signer, - }, nil -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgOptOut) ValidateBasic() error { - if err := validateDeprecatedChainId(msg.ChainId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgOptOut, "ChainId: %s", err.Error()) - } - - if err := ccvtypes.ValidateConsumerId(msg.ConsumerId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgOptOut, "ConsumerId: %s", err.Error()) - } - - if err := validateProviderAddress(msg.ProviderAddr, msg.Signer); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgOptOut, "ProviderAddr: %s", err.Error()) - } - - return nil -} - -// NewMsgSetConsumerCommissionRate creates a new MsgSetConsumerCommissionRate msg instance. -func NewMsgSetConsumerCommissionRate( - consumerId string, - commission math.LegacyDec, - providerValidatorAddress sdk.ValAddress, - signer string, -) *MsgSetConsumerCommissionRate { - return &MsgSetConsumerCommissionRate{ - ConsumerId: consumerId, - Rate: commission, - ProviderAddr: providerValidatorAddress.String(), - Signer: signer, - } -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgSetConsumerCommissionRate) ValidateBasic() error { - if err := validateDeprecatedChainId(msg.ChainId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSetConsumerCommissionRate, "ChainId: %s", err.Error()) - } - - if err := ccvtypes.ValidateConsumerId(msg.ConsumerId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSetConsumerCommissionRate, "ConsumerId: %s", err.Error()) - } - - if err := validateProviderAddress(msg.ProviderAddr, msg.Signer); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgSetConsumerCommissionRate, "ProviderAddr: %s", err.Error()) - } - - if msg.Rate.IsNegative() || msg.Rate.GT(math.LegacyOneDec()) { - return errorsmod.Wrapf(ErrInvalidMsgSetConsumerCommissionRate, "consumer commission rate should be in the range [0, 1]") - } - - return nil -} - -// NewMsgCreateConsumer creates a new MsgCreateConsumer instance -func NewMsgCreateConsumer(submitter, chainId string, metadata ConsumerMetadata, - initializationParameters *ConsumerInitializationParameters, powerShapingParameters *PowerShapingParameters, -) (*MsgCreateConsumer, error) { - return &MsgCreateConsumer{ - Submitter: submitter, - ChainId: chainId, - Metadata: metadata, - InitializationParameters: initializationParameters, - PowerShapingParameters: powerShapingParameters, - }, nil -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgCreateConsumer) ValidateBasic() error { - if err := ValidateStringField("ChainId", msg.ChainId, cmttypes.MaxChainIDLen); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, "ChainId: %s", err.Error()) - } - - // With permissionless ICS, we can have multiple consumer chains with the exact same chain id. - // However, as we already have the Neutron and Stride Top N chains running, as a first step we would like to - // prevent permissionless chains from re-using the chain ids of Neutron and Stride. Note that this is just a - // preliminary measure that will be removed later on as part of: - // TODO (#2242): find a better way of ignoring past misbehaviors - if msg.ChainId == "neutron-1" || msg.ChainId == "stride-1" { - return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, - "cannot reuse chain ids of existing Neutron and Stride Top N consumer chains") - } - - if err := ValidateConsumerMetadata(msg.Metadata); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, "Metadata: %s", err.Error()) - } - - if msg.InitializationParameters != nil { - if err := ValidateInitializationParameters(*msg.InitializationParameters); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, "InitializationParameters: %s", err.Error()) - } - } - - if msg.PowerShapingParameters != nil { - if msg.PowerShapingParameters.Top_N != 0 { - return fmt.Errorf("cannot create a Top N chain through `MsgCreateConsumer`; " + - "first create the chain and then use `MsgUpdateConsumer` to make the chain Top N") - } - if err := ValidatePowerShapingParameters(*msg.PowerShapingParameters); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, "PowerShapingParameters: %s", err.Error()) - } } - return nil } -// NewMsgUpdateConsumer creates a new MsgUpdateConsumer instance -func NewMsgUpdateConsumer(owner, consumerId, ownerAddress string, metadata *ConsumerMetadata, - initializationParameters *ConsumerInitializationParameters, powerShapingParameters *PowerShapingParameters, -) (*MsgUpdateConsumer, error) { - return &MsgUpdateConsumer{ - Owner: owner, - ConsumerId: consumerId, - NewOwnerAddress: ownerAddress, - Metadata: metadata, - InitializationParameters: initializationParameters, - PowerShapingParameters: powerShapingParameters, - }, nil -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgUpdateConsumer) ValidateBasic() error { - if err := ccvtypes.ValidateConsumerId(msg.ConsumerId); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgUpdateConsumer, "ConsumerId: %s", err.Error()) - } - - // Note that NewOwnerAddress is validated when handling the message in UpdateConsumer - - if msg.Metadata != nil { - if err := ValidateConsumerMetadata(*msg.Metadata); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgUpdateConsumer, "Metadata: %s", err.Error()) - } - } - - if msg.InitializationParameters != nil { - if err := ValidateInitializationParameters(*msg.InitializationParameters); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgUpdateConsumer, "InitializationParameters: %s", err.Error()) - } - } - - if msg.PowerShapingParameters != nil { - if err := ValidatePowerShapingParameters(*msg.PowerShapingParameters); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgUpdateConsumer, "PowerShapingParameters: %s", err.Error()) - } - } - - return nil -} - -// NewMsgRemoveConsumer creates a new MsgRemoveConsumer instance -func NewMsgRemoveConsumer(owner, consumerId string) (*MsgRemoveConsumer, error) { - return &MsgRemoveConsumer{ - Owner: owner, - ConsumerId: consumerId, - }, nil -} - -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgRemoveConsumer) ValidateBasic() error { - if err := ccvtypes.ValidateConsumerId(msg.ConsumerId); err != nil { - return err - } - return nil -} - -// -// Validation methods -// - ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) // ParseConsumerKeyFromJson parses the consumer key from a JSON string, // this replaces deserializing a protobuf any. func ParseConsumerKeyFromJson(jsonStr string) (pkType, key string, err error) { @@ -529,7 +215,6 @@ func (msg MsgSubmitConsumerDoubleVoting) ValidateBasic() error { return nil } -<<<<<<< HEAD // Type implements the sdk.Msg interface. func (msg MsgSubmitConsumerDoubleVoting) GetSignBytes() []byte { bz := ccvtypes.ModuleCdc.MustMarshalJSON(&msg) @@ -552,154 +237,6 @@ func (msg MsgSubmitConsumerDoubleVoting) GetSigners() []sdk.AccAddress { // sign the msg as well. func (msg *MsgConsumerAddition) GetSigners() []sdk.AccAddress { valAddr, err := sdk.ValAddressFromBech32(msg.Authority) -======= -// ValidateStringField validates that a string `field` satisfies the following properties: -// - is not empty -// - has at most `maxLength` characters -func ValidateStringField(nameOfTheField, field string, maxLength int) error { - if strings.TrimSpace(field) == "" { - return fmt.Errorf("%s cannot be empty", nameOfTheField) - } else if len(field) > maxLength { - return fmt.Errorf("%s is too long; got: %d, max: %d", nameOfTheField, len(field), maxLength) - } - return nil -} - -// TruncateString truncates a string to maximum length characters -func TruncateString(str string, maxLength int) string { - if maxLength <= 0 { - return "" - } - - truncated := "" - count := 0 - for _, char := range str { - truncated += string(char) - count++ - if count >= maxLength { - break - } - } - return truncated -} - -// ValidateConsumerMetadata validates that all the provided metadata are in the expected range -func ValidateConsumerMetadata(metadata ConsumerMetadata) error { - if err := ValidateStringField("name", metadata.Name, MaxNameLength); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerMetadata, "Name: %s", err.Error()) - } - - if err := ValidateStringField("description", metadata.Description, MaxDescriptionLength); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerMetadata, "Description: %s", err.Error()) - } - - if err := ValidateStringField("metadata", metadata.Metadata, MaxMetadataLength); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerMetadata, "Metadata: %s", err.Error()) - } - - return nil -} - -// ValidateConsAddressList validates a list of consensus addresses -func ValidateConsAddressList(list []string, maxLength int) error { - if len(list) > maxLength { - return fmt.Errorf("consensus address list too long; got: %d, max: %d", len(list), maxLength) - } - for _, address := range list { - _, err := sdk.ConsAddressFromBech32(address) - if err != nil { - return fmt.Errorf("invalid address %s: %s", address, err.Error()) - } - } - return nil -} - -// ValidatePowerShapingParameters validates that all the provided power-shaping parameters are in the expected range -func ValidatePowerShapingParameters(powerShapingParameters PowerShapingParameters) error { - // Top N corresponds to the top N% of validators that have to validate the consumer chain and can only be 0 (for an - // Opt In chain) or in the range [50, 100] (for a Top N chain). - if powerShapingParameters.Top_N != 0 && (powerShapingParameters.Top_N < 50 || powerShapingParameters.Top_N > 100) { - return errorsmod.Wrap(ErrInvalidPowerShapingParameters, "Top N can either be 0 or in the range [50, 100]") - } - - if powerShapingParameters.ValidatorsPowerCap > 100 { - return errorsmod.Wrap(ErrInvalidPowerShapingParameters, "ValidatorsPowerCap has to be in the range [0, 100]") - } - - if err := ValidateConsAddressList(powerShapingParameters.Allowlist, MaxValidatorCount); err != nil { - return errorsmod.Wrapf(ErrInvalidPowerShapingParameters, "Allowlist: %s", err.Error()) - } - if err := ValidateConsAddressList(powerShapingParameters.Denylist, MaxValidatorCount); err != nil { - return errorsmod.Wrapf(ErrInvalidPowerShapingParameters, "Denylist: %s", err.Error()) - } - - return nil -} - -// ValidateInitializationParameters validates that all the provided parameters are in the expected range -func ValidateInitializationParameters(initializationParameters ConsumerInitializationParameters) error { - if initializationParameters.InitialHeight.IsZero() { - return errorsmod.Wrap(ErrInvalidConsumerInitializationParameters, "InitialHeight cannot be zero") - } - - if err := ValidateByteSlice(initializationParameters.GenesisHash, MaxHashLength); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "GenesisHash: %s", err.Error()) - } - - if err := ValidateByteSlice(initializationParameters.BinaryHash, MaxHashLength); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "BinaryHash: %s", err.Error()) - } - - if err := ccvtypes.ValidateStringFraction(initializationParameters.ConsumerRedistributionFraction); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "ConsumerRedistributionFraction: %s", err.Error()) - } - - if err := ccvtypes.ValidatePositiveInt64(initializationParameters.BlocksPerDistributionTransmission); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "BlocksPerDistributionTransmission: %s", err.Error()) - } - - if err := ccvtypes.ValidateDistributionTransmissionChannel(initializationParameters.DistributionTransmissionChannel); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "DistributionTransmissionChannel: %s", err.Error()) - } - - if err := ccvtypes.ValidatePositiveInt64(initializationParameters.HistoricalEntries); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "HistoricalEntries: %s", err.Error()) - } - - if err := ccvtypes.ValidateDuration(initializationParameters.CcvTimeoutPeriod); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "CcvTimeoutPeriod: %s", err.Error()) - } - - if err := ccvtypes.ValidateDuration(initializationParameters.TransferTimeoutPeriod); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "TransferTimeoutPeriod: %s", err.Error()) - } - - if err := ccvtypes.ValidateDuration(initializationParameters.UnbondingPeriod); err != nil { - return errorsmod.Wrapf(ErrInvalidConsumerInitializationParameters, "UnbondingPeriod: %s", err.Error()) - } - - return nil -} - -func ValidateByteSlice(hash []byte, maxLength int) error { - if len(hash) > maxLength { - return fmt.Errorf("hash is too long; got: %d, max: %d", len(hash), maxLength) - } - return nil -} - -func validateDeprecatedChainId(chainId string) error { - if strings.TrimSpace(chainId) != "" { - return fmt.Errorf("found non-empty chainId(%s); chainId is deprecated, use consumerId instead", chainId) - } - - return nil -} - -// validateProviderAddress validates that the address is a sdk.ValAddress in Bech32 string format -func validateProviderAddress(addr, signer string) error { - valAddr, err := sdk.ValAddressFromBech32(addr) ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) if err != nil { // same behavior as in cosmos-sdk panic(err) diff --git a/x/ccv/provider/types/msg_test.go b/x/ccv/provider/types/msg_test.go index eed4e9cd1d..4ef2a7efc8 100644 --- a/x/ccv/provider/types/msg_test.go +++ b/x/ccv/provider/types/msg_test.go @@ -9,552 +9,6 @@ import ( "github.com/stretchr/testify/require" ) -<<<<<<< HEAD -======= -func TestValidateStringField(t *testing.T) { - testCases := []struct { - name string - field string - maxLength int - valid bool - }{ - { - name: "invalid: empty", - field: "", - maxLength: 5, - valid: false, - }, - { - name: "invalid: too long", - field: "this field is too long", - maxLength: 5, - valid: false, - }, - { - name: "valid", - field: "valid", - maxLength: 5, - valid: true, - }, - } - - for _, tc := range testCases { - err := types.ValidateStringField(tc.name, tc.field, tc.maxLength) - if tc.valid { - require.NoError(t, err, tc.name) - } else { - require.Error(t, err, tc.name) - } - } -} - -func TestTruncateString(t *testing.T) { - testCases := []struct { - str string - maxLength int - expStr string - }{ - {"drink", 3, "dri"}, - {"drink", 6, "drink"}, - {"drink", 0, ""}, - {"drink", -1, ""}, - {"drink", 100, "drink"}, - {"pub", 100, "pub"}, - {"こんにちは", 3, "こんに"}, - } - - for _, tc := range testCases { - truncated := types.TruncateString(tc.str, tc.maxLength) - require.Equal(t, tc.expStr, truncated) - } -} - -func TestValidateConsumerMetadata(t *testing.T) { - generateLongString := func(length int) string { - result := make([]byte, length) - for i := range result { - result[i] = byte('a') - } - return string(result) - } - - testCases := []struct { - name string - metadata types.ConsumerMetadata - valid bool - }{ - { - name: "valid", - metadata: types.ConsumerMetadata{ - Name: "name", - Description: "description", - Metadata: "metadata", - }, - valid: true, - }, - { - name: "valid with long strings", - metadata: types.ConsumerMetadata{ - Name: generateLongString(types.MaxNameLength), - Description: generateLongString(types.MaxDescriptionLength), - Metadata: generateLongString(types.MaxMetadataLength), - }, - valid: true, - }, - { - name: "invalid name", - metadata: types.ConsumerMetadata{ - Name: generateLongString(types.MaxNameLength + 1), - Description: "description", - Metadata: "metadata", - }, - valid: false, - }, - { - name: "invalid description", - metadata: types.ConsumerMetadata{ - Name: "name", - Description: generateLongString(types.MaxDescriptionLength + 1), - Metadata: "metadata", - }, - valid: false, - }, - { - name: "invalid metadata", - metadata: types.ConsumerMetadata{ - Name: "name", - Description: "description", - Metadata: generateLongString(types.MaxMetadataLength + 1), - }, - valid: false, - }, - } - - for _, tc := range testCases { - err := types.ValidateConsumerMetadata(tc.metadata) - if tc.valid { - require.NoError(t, err, tc.name) - } else { - require.Error(t, err, tc.name) - } - } -} - -func TestValidateInitializationParameters(t *testing.T) { - now := time.Now().UTC() - coolStr := "Cosmos Hub is the best place to launch a chain. Interchain Security is awesome." - tooLongHash := []byte(coolStr) - - testCases := []struct { - name string - params types.ConsumerInitializationParameters - valid bool - }{ - { - name: "valid", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - valid: true, - }, - { - name: "invalid - zero height", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.ZeroHeight(), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - valid: false, - }, - { - name: "invalid - hash too long", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: tooLongHash, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - valid: false, - }, - { - name: "invalid - zero spawn time", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: time.Time{}, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - valid: true, - }, - { - name: "invalid - zero duration", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: 0, - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - valid: false, - }, - { - name: "invalid -- ConsumerRedistributionFraction > 1", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "1.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - valid: false, - }, - { - name: "invalid -- ConsumerRedistributionFraction wrong format", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: coolStr, - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - valid: false, - }, - { - name: "invalid - BlocksPerDistributionTransmission zero", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 0, - HistoricalEntries: 10000, - DistributionTransmissionChannel: "", - }, - valid: false, - }, - { - name: "invalid - HistoricalEntries zero", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 0, - DistributionTransmissionChannel: "", - }, - valid: false, - }, - { - name: "invalid - DistributionTransmissionChannel too long", - params: types.ConsumerInitializationParameters{ - InitialHeight: clienttypes.NewHeight(3, 4), - GenesisHash: []byte{0x01}, - BinaryHash: []byte{0x01}, - SpawnTime: now, - UnbondingPeriod: time.Duration(100000000000), - CcvTimeoutPeriod: time.Duration(100000000000), - TransferTimeoutPeriod: time.Duration(100000000000), - ConsumerRedistributionFraction: "0.75", - BlocksPerDistributionTransmission: 10, - HistoricalEntries: 10000, - DistributionTransmissionChannel: coolStr, - }, - valid: false, - }, - } - - for _, tc := range testCases { - err := types.ValidateInitializationParameters(tc.params) - if tc.valid { - require.NoError(t, err, tc.name) - } else { - require.Error(t, err, tc.name) - } - } -} - -func TestValidateConsAddressList(t *testing.T) { - consAddr1 := "cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq" - consAddr2 := "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39" - invalidConsAddr := "cosmosvalcons1nx7n5uh0ztxsynn4sje6ey" - - testCases := []struct { - name string - list []string - maxLength int - valid bool - }{ - { - name: "valid - empty list", - list: []string{}, - maxLength: 10, - valid: true, - }, - { - name: "valid - non-empty list", - list: []string{consAddr1, consAddr2}, - maxLength: 10, - valid: true, - }, - { - name: "invalid - address with wrong format", - list: []string{invalidConsAddr}, - maxLength: 10, - valid: false, - }, - { - name: "invalid - empty address", - list: []string{""}, - maxLength: 10, - valid: false, - }, - { - name: "invalid - list length", - list: []string{consAddr1, consAddr2}, - maxLength: 1, - valid: false, - }, - } - - for _, tc := range testCases { - err := types.ValidateConsAddressList(tc.list, tc.maxLength) - if tc.valid { - require.NoError(t, err, tc.name) - } else { - require.Error(t, err, tc.name) - } - } -} - -func TestValidateByteSlice(t *testing.T) { - testCases := []struct { - name string - slice []byte - maxLength int - valid bool - }{ - { - name: "valid: empty", - slice: []byte{}, - maxLength: 5, - valid: true, - }, - { - name: "invalid: too long", - slice: []byte{0x01, 0x02}, - maxLength: 1, - valid: false, - }, - { - name: "valid", - slice: []byte{0x01, 0x02}, - maxLength: 5, - valid: true, - }, - } - - for _, tc := range testCases { - err := types.ValidateByteSlice(tc.slice, tc.maxLength) - if tc.valid { - require.NoError(t, err, tc.name) - } else { - require.Error(t, err, tc.name) - } - } -} - -func TestMsgCreateConsumerValidateBasic(t *testing.T) { - testCases := []struct { - name string - chainId string - powerShapingParameters *types.PowerShapingParameters - expPass bool - }{ - { - "empty chain id", - "", - nil, // no power-shaping parameters - false, - }, - { - "empty chain id after trimming", - " ", - nil, // no power-shaping parameters - false, - }, - { - "neutron chain id that cannot be reused", - "neutron-1", - nil, // no power-shaping parameters - false, - }, - { - "stride chain id that cannot be reused", - "stride-1", - nil, // no power-shaping parameters - false, - }, - { - "valid chain id", - "somechain-1", - nil, // no power-shaping parameters - true, - }, - { - "valid chain id and invalid power-shaping parameters", - "somechain-1", - &types.PowerShapingParameters{Top_N: 51}, // TopN cannot be > 0 in MsgCreateConsumer - false, - }, - } - - for _, tc := range testCases { - validConsumerMetadata := types.ConsumerMetadata{Name: "name", Description: "description", Metadata: "metadata"} - msg, err := types.NewMsgCreateConsumer("submitter", tc.chainId, validConsumerMetadata, nil, tc.powerShapingParameters) - require.NoError(t, err) - err = msg.ValidateBasic() - if tc.expPass { - require.NoError(t, err, "valid case: %s should not return error. got %w", tc.name, err) - } else { - require.Error(t, err, "invalid case: '%s' must return error but got none", tc.name) - } - } -} - -func TestMsgUpdateConsumerValidateBasic(t *testing.T) { - consAddr1 := "cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq" - consAddr2 := "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39" - consAddr3 := "cosmosvalcons1muys5jyqk4xd27e208nym85kn0t4zjcfeu63fe" - - testCases := []struct { - name string - powerShapingParameters types.PowerShapingParameters - expPass bool - }{ - { - "success", - types.PowerShapingParameters{ - Top_N: 50, - ValidatorsPowerCap: 100, - ValidatorSetCap: 34, - Allowlist: []string{consAddr1}, - Denylist: nil, - MinStake: 0, - AllowInactiveVals: false, - }, - true, - }, - { - "top N is invalid", - types.PowerShapingParameters{ - Top_N: 10, - ValidatorsPowerCap: 0, - ValidatorSetCap: 0, - Allowlist: nil, - Denylist: nil, - }, - false, - }, - { - "validators power cap is invalid", - types.PowerShapingParameters{ - Top_N: 50, - ValidatorsPowerCap: 101, - ValidatorSetCap: 0, - Allowlist: nil, - Denylist: nil, - MinStake: 0, - AllowInactiveVals: false, - }, - false, - }, - { - "valid proposal", - types.PowerShapingParameters{ - Top_N: 54, - ValidatorsPowerCap: 92, - ValidatorSetCap: 0, - Allowlist: []string{consAddr1}, - Denylist: []string{consAddr2, consAddr3}, - MinStake: 0, - AllowInactiveVals: false, - }, - true, - }, - } - - for _, tc := range testCases { - // TODO (PERMISSIONLESS) add more tests - msg, _ := types.NewMsgUpdateConsumer("", "0", "cosmos1p3ucd3ptpw902fluyjzhq3ffgq4ntddac9sa3s", nil, nil, &tc.powerShapingParameters) - err := msg.ValidateBasic() - if tc.expPass { - require.NoError(t, err, "valid case: %s should not return error. got %w", tc.name, err) - } else { - require.Error(t, err, "invalid case: '%s' must return error but got none", tc.name) - } - } -} - ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) func TestMsgAssignConsumerKeyValidateBasic(t *testing.T) { cId1 := cryptoutil.NewCryptoIdentityFromIntSeed(35443543534) cId2 := cryptoutil.NewCryptoIdentityFromIntSeed(65465464564) diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go index e2bf04424f..0e93388e0f 100644 --- a/x/ccv/provider/types/tx.pb.go +++ b/x/ccv/provider/types/tx.pb.go @@ -424,7 +424,7 @@ type MsgConsumerAddition struct { // channel is created on top of the same connection as the CCV channel. // Note that transfer_channel_id is the ID of the channel end on the consumer // chain. it is most relevant for chains performing a sovereign to consumer - // changeover in order to maintain the existing ibc transfer channel + // changeover in order to maintan the existing ibc transfer channel DistributionTransmissionChannel string `protobuf:"bytes,12,opt,name=distribution_transmission_channel,json=distributionTransmissionChannel,proto3" json:"distribution_transmission_channel,omitempty"` // Corresponds to the percentage of validators that have to validate the chain under the Top N case. // For example, 53 corresponds to a Top 53% chain, meaning that the top 53% provider validators by voting power diff --git a/x/ccv/types/errors.go b/x/ccv/types/errors.go index d155c17c1a..e1175fddc4 100644 --- a/x/ccv/types/errors.go +++ b/x/ccv/types/errors.go @@ -22,10 +22,5 @@ var ( ErrDuplicateConsumerChain = errorsmod.Register(ModuleName, 14, "consumer chain already exists") ErrConsumerChainNotFound = errorsmod.Register(ModuleName, 15, "consumer chain not found") ErrInvalidDoubleVotingEvidence = errorsmod.Register(ModuleName, 16, "invalid consumer double voting evidence") -<<<<<<< HEAD -======= - ErrStoreKeyNotFound = errorsmod.Register(ModuleName, 17, "store key not found") - ErrStoreUnmarshal = errorsmod.Register(ModuleName, 18, "cannot unmarshal value from store") - ErrInvalidConsumerId = errorsmod.Register(ModuleName, 19, "invalid consumer id") ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) + ErrInvalidConsumerId = errorsmod.Register(ModuleName, 17, "invalid consumer id") ) diff --git a/x/ccv/types/shared_consumer.pb.go b/x/ccv/types/shared_consumer.pb.go index 5fffae9f37..73f00216f1 100644 --- a/x/ccv/types/shared_consumer.pb.go +++ b/x/ccv/types/shared_consumer.pb.go @@ -75,7 +75,8 @@ type ConsumerParams struct { ProviderRewardDenoms []string `protobuf:"bytes,12,rep,name=provider_reward_denoms,json=providerRewardDenoms,proto3" json:"provider_reward_denoms,omitempty"` // The period after which a consumer can retry sending a throttled packet. RetryDelayPeriod time.Duration `protobuf:"bytes,13,opt,name=retry_delay_period,json=retryDelayPeriod,proto3,stdduration" json:"retry_delay_period"` - // The consumer ID of this consumer chain + // The consumer ID of this consumer chain. Used by the consumer module to send + // ICS rewards. ConsumerId string `protobuf:"bytes,14,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` } @@ -350,64 +351,10 @@ func init() { } var fileDescriptor_d0a8be0efc64dfbc = []byte{ -<<<<<<< HEAD - // 817 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x41, 0x73, 0xdc, 0x34, - 0x14, 0x8e, 0xb3, 0x25, 0xdd, 0x68, 0x93, 0xa6, 0x88, 0x50, 0x4c, 0x3a, 0xb3, 0x71, 0x03, 0x87, - 0x1d, 0x98, 0xda, 0x24, 0x94, 0x61, 0x86, 0x1b, 0x49, 0x28, 0xa5, 0x87, 0x64, 0xeb, 0x84, 0x32, - 0x03, 0x07, 0x8d, 0x2c, 0xbd, 0x5d, 0x6b, 0xb0, 0x25, 0x8f, 0x24, 0x3b, 0xe4, 0x17, 0x70, 0xe5, - 0xc8, 0x4f, 0x2a, 0xb7, 0x1e, 0x39, 0x01, 0x93, 0xfc, 0x11, 0xc6, 0xb2, 0x9d, 0x78, 0x19, 0x02, - 0xe9, 0x4d, 0x4f, 0xef, 0xfb, 0x3e, 0xfb, 0x7b, 0xd2, 0x7b, 0x42, 0x9f, 0x08, 0x69, 0x41, 0xb3, - 0x94, 0x0a, 0x49, 0x0c, 0xb0, 0x52, 0x0b, 0x7b, 0x1e, 0x31, 0x56, 0x45, 0xd5, 0x6e, 0x64, 0x52, - 0xaa, 0x81, 0x13, 0xa6, 0xa4, 0x29, 0x73, 0xd0, 0x61, 0xa1, 0x95, 0x55, 0x78, 0xeb, 0x5f, 0x18, - 0x21, 0x63, 0x55, 0x58, 0xed, 0x6e, 0x3d, 0xb4, 0x20, 0x39, 0xe8, 0x5c, 0x48, 0x1b, 0xd1, 0x84, - 0x89, 0xc8, 0x9e, 0x17, 0x60, 0x1a, 0xe2, 0x56, 0x24, 0x12, 0x16, 0x65, 0x62, 0x9e, 0x5a, 0x96, - 0x09, 0x90, 0xd6, 0x44, 0x3d, 0x74, 0xb5, 0xdb, 0x8b, 0x5a, 0xc2, 0x78, 0xae, 0xd4, 0x3c, 0x83, - 0xc8, 0x45, 0x49, 0x39, 0x8b, 0x78, 0xa9, 0xa9, 0x15, 0x4a, 0xb6, 0xf9, 0xcd, 0xb9, 0x9a, 0x2b, - 0xb7, 0x8c, 0xea, 0x55, 0xb3, 0xbb, 0x73, 0xb9, 0x82, 0xee, 0x1d, 0xb4, 0xbf, 0x3c, 0xa5, 0x9a, - 0xe6, 0x06, 0xfb, 0xe8, 0x2e, 0x48, 0x9a, 0x64, 0xc0, 0x7d, 0x2f, 0xf0, 0x26, 0xc3, 0xb8, 0x0b, - 0xf1, 0x31, 0xfa, 0x30, 0xc9, 0x14, 0xfb, 0xd1, 0x90, 0x02, 0x34, 0xe1, 0xc2, 0x58, 0x2d, 0x92, - 0xb2, 0xfe, 0x06, 0xb1, 0x9a, 0x4a, 0x93, 0x0b, 0x63, 0x84, 0x92, 0xfe, 0x72, 0xe0, 0x4d, 0x06, - 0xf1, 0xa3, 0x06, 0x3b, 0x05, 0x7d, 0xd8, 0x43, 0x9e, 0xf6, 0x80, 0xf8, 0x39, 0x7a, 0x74, 0xa3, - 0x0a, 0x61, 0x29, 0x95, 0x12, 0x32, 0x7f, 0x10, 0x78, 0x93, 0xd5, 0x78, 0x9b, 0xdf, 0x20, 0x72, - 0xd0, 0xc0, 0xf0, 0x17, 0x68, 0xab, 0xd0, 0xaa, 0x12, 0x1c, 0x34, 0x99, 0x01, 0x90, 0x42, 0xa9, - 0x8c, 0x50, 0xce, 0x35, 0x31, 0x56, 0xfb, 0x77, 0x9c, 0xc8, 0x83, 0x0e, 0xf1, 0x14, 0x60, 0xaa, - 0x54, 0xf6, 0x25, 0xe7, 0xfa, 0xc4, 0x6a, 0xfc, 0x02, 0x61, 0xc6, 0x2a, 0x62, 0x45, 0x0e, 0xaa, - 0xb4, 0xb5, 0x3b, 0xa1, 0xb8, 0xff, 0x56, 0xe0, 0x4d, 0x46, 0x7b, 0xef, 0x87, 0x4d, 0x61, 0xc3, - 0xae, 0xb0, 0xe1, 0x61, 0x5b, 0xd8, 0xfd, 0xe1, 0xab, 0x3f, 0xb6, 0x97, 0x7e, 0xfd, 0x73, 0xdb, - 0x8b, 0xef, 0x33, 0x56, 0x9d, 0x36, 0xec, 0xa9, 0x23, 0xe3, 0x1f, 0xd0, 0x7b, 0xce, 0xcd, 0x0c, - 0xf4, 0x3f, 0x75, 0x57, 0x6e, 0xaf, 0xfb, 0x6e, 0xa7, 0xb1, 0x28, 0xfe, 0x0c, 0x05, 0xdd, 0x3d, - 0x23, 0x1a, 0x16, 0x4a, 0x38, 0xd3, 0x94, 0xd5, 0x0b, 0xff, 0xae, 0x73, 0x3c, 0xee, 0x70, 0xf1, - 0x02, 0xec, 0x69, 0x8b, 0xc2, 0x8f, 0x11, 0x4e, 0x85, 0xb1, 0x4a, 0x0b, 0x46, 0x33, 0x02, 0xd2, - 0x6a, 0x01, 0xc6, 0x1f, 0xba, 0x03, 0x7c, 0xfb, 0x3a, 0xf3, 0x55, 0x93, 0xc0, 0x47, 0xe8, 0x7e, - 0x29, 0x13, 0x25, 0xb9, 0x90, 0xf3, 0xce, 0xce, 0xea, 0xed, 0xed, 0x6c, 0x5c, 0x91, 0x5b, 0x23, - 0x9f, 0xa3, 0x07, 0x46, 0xcd, 0x2c, 0x51, 0x85, 0x25, 0x75, 0x85, 0x6c, 0xaa, 0xc1, 0xa4, 0x2a, - 0xe3, 0x3e, 0xaa, 0x7f, 0x7f, 0x7f, 0xd9, 0xf7, 0xe2, 0x77, 0x6a, 0xc4, 0x71, 0x61, 0x8f, 0x4b, - 0x7b, 0xda, 0xa5, 0xf1, 0x07, 0x68, 0x5d, 0xc3, 0x19, 0xd5, 0x9c, 0x70, 0x90, 0x2a, 0x37, 0xfe, - 0x28, 0x18, 0x4c, 0x56, 0xe3, 0xb5, 0x66, 0xf3, 0xd0, 0xed, 0xe1, 0x27, 0xe8, 0xea, 0xc0, 0xc9, - 0x22, 0x7a, 0xcd, 0xa1, 0x37, 0xbb, 0x6c, 0xdc, 0x67, 0xbd, 0x40, 0x58, 0x83, 0xd5, 0xe7, 0x84, - 0x43, 0x46, 0xcf, 0x3b, 0x97, 0xeb, 0x6f, 0x70, 0x19, 0x1c, 0xfd, 0xb0, 0x66, 0x37, 0x36, 0x77, - 0x7e, 0xf3, 0xd0, 0x66, 0xd7, 0x65, 0x5f, 0x83, 0x04, 0x23, 0xcc, 0x89, 0xa5, 0x16, 0xf0, 0x33, - 0xb4, 0x52, 0xb8, 0xae, 0x73, 0xad, 0x36, 0xda, 0xfb, 0x28, 0xbc, 0x79, 0x5e, 0x84, 0x8b, 0x7d, - 0xba, 0x7f, 0xa7, 0xfe, 0x60, 0xdc, 0xf2, 0xf1, 0x73, 0x34, 0xec, 0xdc, 0xb8, 0xfe, 0x1b, 0xed, - 0x4d, 0xfe, 0x4b, 0x6b, 0xda, 0x62, 0xbf, 0x91, 0x33, 0xd5, 0x2a, 0x5d, 0xf1, 0xf1, 0x43, 0xb4, - 0x2a, 0xe1, 0x8c, 0x38, 0xa6, 0x6b, 0xbf, 0x61, 0x3c, 0x94, 0x70, 0x76, 0x50, 0xc7, 0x3b, 0x3f, - 0x2f, 0xa3, 0xb5, 0x3e, 0x1b, 0x1f, 0xa1, 0xb5, 0x66, 0x44, 0x11, 0x53, 0x7b, 0x6a, 0x9d, 0x7c, - 0x1c, 0x8a, 0x84, 0x85, 0xfd, 0x01, 0x16, 0xf6, 0x46, 0x56, 0xed, 0xc6, 0xed, 0xba, 0x32, 0xc4, - 0x23, 0x76, 0x1d, 0xe0, 0xef, 0xd0, 0x46, 0x7d, 0x69, 0x41, 0x9a, 0xd2, 0xb4, 0x92, 0x8d, 0xa1, - 0xf0, 0x7f, 0x25, 0x3b, 0x5a, 0xa3, 0x7a, 0x8f, 0x2d, 0xc4, 0xf8, 0x08, 0x6d, 0x08, 0x29, 0xac, - 0xa0, 0x19, 0xa9, 0x68, 0x46, 0x0c, 0x58, 0x7f, 0x10, 0x0c, 0x26, 0xa3, 0xbd, 0xa0, 0xaf, 0x53, - 0x4f, 0xe2, 0xf0, 0x25, 0xcd, 0x04, 0xa7, 0x56, 0xe9, 0x6f, 0x0b, 0x4e, 0x2d, 0xb4, 0x15, 0x5a, - 0x6f, 0xe9, 0x2f, 0x69, 0x76, 0x02, 0x76, 0xff, 0xe8, 0xd5, 0xc5, 0xd8, 0x7b, 0x7d, 0x31, 0xf6, - 0xfe, 0xba, 0x18, 0x7b, 0xbf, 0x5c, 0x8e, 0x97, 0x5e, 0x5f, 0x8e, 0x97, 0x7e, 0xbf, 0x1c, 0x2f, - 0x7d, 0xff, 0x64, 0x2e, 0x6c, 0x5a, 0x26, 0x21, 0x53, 0x79, 0xc4, 0x94, 0xc9, 0x95, 0x89, 0xae, - 0xcf, 0xe2, 0xf1, 0xd5, 0xcb, 0x51, 0x7d, 0x16, 0xfd, 0xe4, 0x9e, 0x0f, 0x37, 0xf8, 0x93, 0x15, - 0x77, 0xa9, 0x3e, 0xfd, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x00, 0xe4, 0xb0, 0x69, 0x66, 0x06, 0x00, -======= // 833 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcf, 0x73, 0xdc, 0x34, 0x14, 0x8e, 0xb3, 0x25, 0xd9, 0x68, 0xf3, 0xa3, 0x88, 0x50, 0x4c, 0x3a, 0xb3, 0xd9, 0x06, 0x0e, - 0x3b, 0x30, 0xb5, 0x49, 0xe8, 0xc0, 0x0c, 0x37, 0x92, 0x50, 0xda, 0x1e, 0x92, 0xad, 0x13, 0xca, + 0x3b, 0x30, 0xb5, 0x49, 0x28, 0xc3, 0x0c, 0x37, 0x92, 0x50, 0xda, 0x1e, 0x92, 0xad, 0x13, 0xca, 0x0c, 0x1c, 0x34, 0xb2, 0xf4, 0x76, 0xad, 0xc1, 0x96, 0x3c, 0x92, 0xec, 0x90, 0x3b, 0x33, 0x5c, 0x39, 0xf2, 0x27, 0x95, 0x5b, 0x8f, 0x9c, 0x80, 0x49, 0xfe, 0x11, 0xc6, 0xb2, 0xbd, 0xf1, 0x32, 0x04, 0xda, 0x9b, 0x9f, 0xf4, 0x7d, 0x9f, 0xf5, 0xbd, 0xa7, 0xf7, 0x84, 0x3e, 0x11, 0xd2, 0x82, @@ -456,8 +403,7 @@ var fileDescriptor_d0a8be0efc64dfbc = []byte{ 0xbf, 0xae, 0x86, 0xde, 0x2f, 0xd7, 0xc3, 0xa5, 0x57, 0xd7, 0xc3, 0xa5, 0xdf, 0xaf, 0x87, 0x4b, 0xdf, 0x3d, 0x9a, 0x09, 0x9b, 0x14, 0x71, 0xc0, 0x54, 0x16, 0x32, 0x65, 0x32, 0x65, 0xc2, 0x9b, 0x5a, 0x3c, 0x9c, 0x3f, 0x2d, 0xe5, 0x67, 0xe1, 0x8f, 0xee, 0x7d, 0x71, 0x2f, 0x43, 0xbc, 0xe2, - 0x6e, 0xdd, 0xa7, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0xbc, 0xf0, 0xde, 0x5e, 0x87, 0x06, 0x00, ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) + 0x6e, 0xdd, 0xa7, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x72, 0xc0, 0x25, 0x87, 0x06, 0x00, 0x00, } diff --git a/x/ccv/types/shared_params.go b/x/ccv/types/shared_params.go index 3f7eb9240f..e4b4fbdf28 100644 --- a/x/ccv/types/shared_params.go +++ b/x/ccv/types/shared_params.go @@ -6,12 +6,7 @@ import ( "strings" "time" -<<<<<<< HEAD -======= - ibchost "github.com/cosmos/ibc-go/v8/modules/core/24-host" - errorsmod "cosmossdk.io/errors" ->>>>>>> 0d782959 (feat!: add memo to IBC transfers of ICS rewards (#2290)) "cosmossdk.io/math" ibchost "github.com/cosmos/ibc-go/v8/modules/core/24-host" diff --git a/x/ccv/types/shared_params_test.go b/x/ccv/types/shared_params_test.go index 9d2bbfce00..ceb576e3e4 100644 --- a/x/ccv/types/shared_params_test.go +++ b/x/ccv/types/shared_params_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/interchain-security/v6/x/ccv/types" + "github.com/cosmos/interchain-security/v5/x/ccv/types" ) func TestValidateConsumerId(t *testing.T) {