Skip to content

Commit

Permalink
Drop duplicate spawn/stop proposals (#254)
Browse files Browse the repository at this point in the history
* drop duplicate create / stop proposals

* small test fix for #254 (#258)

two different chain ids

* return nil on duplicate proposal

* minor changes to UTs

Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com>
  • Loading branch information
mpoke and shaspitz authored Aug 9, 2022
1 parent 7babed4 commit b2a272f
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 18 deletions.
11 changes: 11 additions & 0 deletions x/ccv/provider/keeper/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ func (k Keeper) StopConsumerChainProposal(ctx sdk.Context, p *types.StopConsumer
// StopConsumerChain cleans up the states for the given consumer chain ID and, if the given lockUbd is false,
// it completes the outstanding unbonding operations lock by the consumer chain.
func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, lockUbd, closeChan bool) (err error) {
// check that a client for chainID exists
if _, found := k.GetConsumerClientId(ctx, chainID); !found {
// drop the proposal
return nil
}

// clean up states
k.DeleteConsumerClientId(ctx, chainID)
Expand Down Expand Up @@ -113,6 +118,12 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, lockUbd, clos
// 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, chainID string, initialHeight clienttypes.Height, lockUbdOnTimeout bool) error {
// check that a client for this chain does not exist
if _, found := k.GetConsumerClientId(ctx, chainID); found {
// drop the proposal
return nil
}

// Use the unbonding period on the provider to
// compute the unbonding period on the consumer
unbondingTime := utils.ComputeConsumerUnbondingPeriod(k.stakingKeeper.UnbondingTime(ctx))
Expand Down
14 changes: 7 additions & 7 deletions x/ccv/provider/keeper/proposal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func (suite *KeeperTestSuite) TestCreateConsumerChainProposal() {
suite.Require().NoError(err)
proposal, ok = content.(*types.CreateConsumerChainProposal)
suite.Require().True(ok)
proposal.LockUnbondingOnTimeout = lockUbdOnTimeout
}, true, true,
},
{
Expand All @@ -76,6 +77,7 @@ func (suite *KeeperTestSuite) TestCreateConsumerChainProposal() {
suite.Require().NoError(err)
proposal, ok = content.(*types.CreateConsumerChainProposal)
suite.Require().True(ok)
proposal.LockUnbondingOnTimeout = lockUbdOnTimeout
}, true, false,
},
}
Expand Down Expand Up @@ -103,9 +105,9 @@ func (suite *KeeperTestSuite) TestCreateConsumerChainProposal() {
suite.Require().Equal(expectedGenesis, consumerGenesis)
suite.Require().NotEqual("", clientId, "consumer client was not created after spawn time reached")
} else {
gotClient := suite.providerChain.App.(*appProvider.App).ProviderKeeper.GetPendingCreateProposal(ctx, proposal.SpawnTime, chainID)
suite.Require().Equal(initialHeight, gotClient.InitialHeight, "pending client not equal to clientstate in proposal")
suite.Require().Equal(lockUbdOnTimeout, gotClient.LockUnbondingOnTimeout, "pending client not equal to clientstate in proposal")
gotProposal := suite.providerChain.App.(*appProvider.App).ProviderKeeper.GetPendingCreateProposal(ctx, proposal.SpawnTime, chainID)
suite.Require().Equal(initialHeight, gotProposal.InitialHeight, "unexpected pending proposal (InitialHeight)")
suite.Require().Equal(lockUbdOnTimeout, gotProposal.LockUnbondingOnTimeout, "unexpected pending proposal (LockUnbondingOnTimeout)")
}
} else {
suite.Require().Error(err, "did not return error on invalid case")
Expand Down Expand Up @@ -148,18 +150,16 @@ func (suite *KeeperTestSuite) TestIteratePendingStopProposal() {

func (suite *KeeperTestSuite) TestIteratePendingClientInfo() {

chainID := suite.consumerChain.ChainID

testCases := []struct {
types.CreateConsumerChainProposal
ExpDeleted bool
}{
{
CreateConsumerChainProposal: types.CreateConsumerChainProposal{ChainId: chainID, SpawnTime: time.Now().UTC()},
CreateConsumerChainProposal: types.CreateConsumerChainProposal{ChainId: "0", SpawnTime: time.Now().UTC()},
ExpDeleted: true,
},
{
CreateConsumerChainProposal: types.CreateConsumerChainProposal{ChainId: chainID, SpawnTime: time.Now().UTC().Add(time.Hour)},
CreateConsumerChainProposal: types.CreateConsumerChainProposal{ChainId: "1", SpawnTime: time.Now().UTC().Add(time.Hour)},
ExpDeleted: false,
},
}
Expand Down
4 changes: 3 additions & 1 deletion x/ccv/provider/proposal_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (
"github.com/cosmos/interchain-security/x/ccv/provider/types"
)

func (suite *ProviderTestSuite) TestCreateConsumerChainProposalHandler() {
// TestConsumerChainProposalHandler tests the handler for consumer chain proposals
// for both CreateConsumerChainProposal and StopConsumerChainProposal
func (suite *ProviderTestSuite) TestConsumerChainProposalHandler() {
var (
ctx sdk.Context
content govtypes.Content
Expand Down
7 changes: 4 additions & 3 deletions x/ccv/provider/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (

// Provider sentinel errors
var (
ErrInvalidProposal = sdkerrors.Register(ModuleName, 1, "invalid create consumer chain proposal")
ErrUnknownConsumerChainId = sdkerrors.Register(ModuleName, 2, "no consumer chain with this chain id")
ErrUnknownConsumerChannelId = sdkerrors.Register(ModuleName, 3, "no consumer chain with this channel id")
ErrInvalidCreateProposal = sdkerrors.Register(ModuleName, 1, "invalid create consumer chain proposal")
ErrInvalidStopProposal = sdkerrors.Register(ModuleName, 2, "invalid stop consumer chain proposal")
ErrUnknownConsumerChainId = sdkerrors.Register(ModuleName, 3, "no consumer chain with this chain id")
ErrUnknownConsumerChannelId = sdkerrors.Register(ModuleName, 4, "no consumer chain with this channel id")
)
14 changes: 7 additions & 7 deletions x/ccv/provider/types/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,22 @@ func (cccp *CreateConsumerChainProposal) ValidateBasic() error {
}

if strings.TrimSpace(cccp.ChainId) == "" {
return sdkerrors.Wrap(ErrInvalidProposal, "consumer chain id must not be blank")
return sdkerrors.Wrap(ErrInvalidCreateProposal, "consumer chain id must not be blank")
}

if cccp.InitialHeight.IsZero() {
return sdkerrors.Wrap(ErrInvalidProposal, "initial height cannot be zero")
return sdkerrors.Wrap(ErrInvalidCreateProposal, "initial height cannot be zero")
}

if len(cccp.GenesisHash) == 0 {
return sdkerrors.Wrap(ErrInvalidProposal, "genesis hash cannot be empty")
return sdkerrors.Wrap(ErrInvalidCreateProposal, "genesis hash cannot be empty")
}
if len(cccp.BinaryHash) == 0 {
return sdkerrors.Wrap(ErrInvalidProposal, "binary hash cannot be empty")
return sdkerrors.Wrap(ErrInvalidCreateProposal, "binary hash cannot be empty")
}

if cccp.SpawnTime.IsZero() {
return sdkerrors.Wrap(ErrInvalidProposal, "spawn time cannot be zero")
return sdkerrors.Wrap(ErrInvalidCreateProposal, "spawn time cannot be zero")
}
return nil
}
Expand Down Expand Up @@ -112,11 +112,11 @@ func (sccp *StopConsumerChainProposal) ValidateBasic() error {
}

if strings.TrimSpace(sccp.ChainId) == "" {
return sdkerrors.Wrap(ErrInvalidProposal, "consumer chain id must not be blank")
return sdkerrors.Wrap(ErrInvalidStopProposal, "consumer chain id must not be blank")
}

if sccp.StopTime.IsZero() {
return sdkerrors.Wrap(ErrInvalidProposal, "spawn time cannot be zero")
return sdkerrors.Wrap(ErrInvalidStopProposal, "spawn time cannot be zero")
}
return nil
}

0 comments on commit b2a272f

Please sign in to comment.