diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index 8a7647cff5..e1bf9cc14f 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -17,7 +17,7 @@ func (k Keeper) HandleOptIn(ctx sdk.Context, chainID string, providerAddr types. if !k.IsConsumerProposedOrRegistered(ctx, chainID) { return errorsmod.Wrapf( types.ErrUnknownConsumerChainId, - "opting in to an unknown consumer chain id: %s", chainID) + "opting in to an unknown consumer chain, with id: %s", chainID) } if k.IsToBeOptedOut(ctx, chainID, providerAddr) { @@ -49,10 +49,12 @@ func (k Keeper) HandleOptIn(ctx sdk.Context, chainID string, providerAddr types. } func (k Keeper) HandleOptOut(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress) error { - if !k.IsConsumerProposedOrRegistered(ctx, chainID) { + if _, found := k.GetConsumerClientId(ctx, chainID); !found { + // A validator can only opt out from a running chain. We check this by checking the consumer client id, because + // `SetConsumerClientId` is set when the chain starts in `CreateConsumerClientInCachedCtx` of `BeginBlockInit`. return errorsmod.Wrapf( types.ErrUnknownConsumerChainId, - "opting out of an unknown consumer chain id: %s", chainID) + "opting out of an unknown or not running consumer chain, with id: %s", chainID) } if k.IsToBeOptedIn(ctx, chainID, providerAddr) { diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index 1ca5285790..4831723bec 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -90,13 +90,13 @@ func TestHandleOptOut(t *testing.T) { providerAddr := types.NewProviderConsAddress([]byte("providerAddr")) - // trying to opt out from a non-proposed and non-registered chain returns an error + // trying to opt out from a not running chain returns an error require.Error(t, providerKeeper.HandleOptOut(ctx, "unknownChainID", providerAddr)) // if validator (`providerAddr`) is to be opted in, then we cancel that the validator is about // to be opted out and do not consider the validator to opt out providerKeeper.SetToBeOptedIn(ctx, "chainID", providerAddr) - providerKeeper.SetProposedConsumerChain(ctx, "chainID", 1) + providerKeeper.SetConsumerClientId(ctx, "chainID", "clientID") require.True(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr)) err := providerKeeper.HandleOptOut(ctx, "chainID", providerAddr) require.NoError(t, err)