Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
### FEATURES

- Add stake validation to vote messages from wasm contracts ([#3949](https://github.com/cosmos/gaia/pull/3949))
- Add stake validation to vote messages from interchain accounts ([#3949](https://github.com/cosmos/gaia/pull/3957))
- Add stake validation to vote messages from interchain accounts ([#3957](https://github.com/cosmos/gaia/pull/3957))
- Add provider ante handler to disable the creation of new consumer chains ([#3959])https://github.com/cosmos/gaia/pull/3959

### BUG-FIXES
- Add missing cosmos_proto.scalar cosmos.Dec annotation to x/liquid LiquidValidator.liquid_shares
Expand Down
1 change: 1 addition & 0 deletions ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) {
ante.NewValidateMemoDecorator(opts.AccountKeeper),
ante.NewConsumeGasForTxSizeDecorator(opts.AccountKeeper),
NewGovVoteDecorator(opts.Codec, opts.StakingKeeper),
NewProviderDecorator(opts.Codec), // Block MsgCreateConsumer messages
ante.NewSetPubKeyDecorator(opts.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
ante.NewValidateSigCountDecorator(opts.AccountKeeper),
ante.NewSigGasConsumeDecorator(opts.AccountKeeper, sigGasConsumer),
Expand Down
67 changes: 67 additions & 0 deletions ante/provider_ante.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package ante

import (
providertypes "github.com/cosmos/interchain-security/v7/x/ccv/provider/types"

errorsmod "cosmossdk.io/errors"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz"

gaiaerrors "github.com/cosmos/gaia/v26/types/errors"
)

const maxWrappedMessageDepthProvider = 4

// ProviderDecorator prevents MsgCreateConsumer messages from being processed
type ProviderDecorator struct {
cdc codec.BinaryCodec
}

func NewProviderDecorator(cdc codec.BinaryCodec) ProviderDecorator {
return ProviderDecorator{
cdc: cdc,
}
}

func (p ProviderDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
Comment thread
dasanchez marked this conversation as resolved.
for _, m := range tx.GetMsgs() {
if err := p.validateMsgRecursive(m, 0); err != nil {
return ctx, err
}
}

return next(ctx, tx, simulate)
}

func (p ProviderDecorator) validateMsgRecursive(m sdk.Msg, iters int) error {
if iters >= maxWrappedMessageDepthProvider {
return errorsmod.Wrap(gaiaerrors.ErrNestedMessageLimitExceeded, "too many wrapped sdk messages")
}

// Handle authz wrapped messages
if msg, ok := m.(*authz.MsgExec); ok {
for _, v := range msg.Msgs {
var innerMsg sdk.Msg
if err := p.cdc.UnpackAny(v, &innerMsg); err != nil {
return errorsmod.Wrap(gaiaerrors.ErrUnauthorized, "cannot unmarshal authz exec msgs")
}
if err := p.validateMsgRecursive(innerMsg, iters+1); err != nil {
return err
}
}
return nil
}

return p.validMsg(m)
}

func (p ProviderDecorator) validMsg(m sdk.Msg) error {
// Block MsgCreateConsumer
if _, ok := m.(*providertypes.MsgCreateConsumer); ok {
return errorsmod.Wrap(gaiaerrors.ErrUnauthorized, "MsgCreateConsumer is disabled")
}

return nil
}
115 changes: 115 additions & 0 deletions ante/provider_ante_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package ante_test

import (
"testing"

"github.com/stretchr/testify/require"

providertypes "github.com/cosmos/interchain-security/v7/x/ccv/provider/types"

"cosmossdk.io/math"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

"github.com/cosmos/gaia/v26/ante"
"github.com/cosmos/gaia/v26/app/helpers"
)

func TestProviderDecorator_BlockMsgCreateConsumer(t *testing.T) {
app := helpers.Setup(t)
ctx := app.NewContext(false)
cdc := app.AppCodec()

decorator := ante.NewProviderDecorator(cdc)

// Create a mock MsgCreateConsumer
msgCreateConsumer := &providertypes.MsgCreateConsumer{
Submitter: "cosmos1abcdef1234567890abcdef1234567890abcdef",
}

// Create a transaction with the MsgCreateConsumer
txBuilder := app.GetTxConfig().NewTxBuilder()
err := txBuilder.SetMsgs(msgCreateConsumer)
require.NoError(t, err)
tx := txBuilder.GetTx()

// Test that the decorator blocks the MsgCreateConsumer
_, err = decorator.AnteHandle(ctx, tx, false, func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
require.Fail(t, "next handler should not be called")
return ctx, nil
})

require.Error(t, err)
require.Contains(t, err.Error(), "MsgCreateConsumer is disabled")
}

func TestProviderDecorator_AllowOtherMessages(t *testing.T) {
app := helpers.Setup(t)
ctx := app.NewContext(false)
cdc := app.AppCodec()

decorator := ante.NewProviderDecorator(cdc)

// Create a normal bank message (should be allowed)
msgSend := &banktypes.MsgSend{
FromAddress: "cosmos1abcdef1234567890abcdef1234567890abcdef",
ToAddress: "cosmos1fedcba0987654321fedcba0987654321fedcba",
Amount: sdk.NewCoins(sdk.NewCoin("uatom", math.NewInt(100))),
}

// Create a transaction with the MsgSend
txBuilder := app.GetTxConfig().NewTxBuilder()
err := txBuilder.SetMsgs(msgSend)
require.NoError(t, err)
tx := txBuilder.GetTx()

// Test that the decorator allows other messages and calls next handler
nextCalled := false
_, err = decorator.AnteHandle(ctx, tx, false, func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
nextCalled = true
return ctx, nil
})

require.NoError(t, err)
require.True(t, nextCalled, "next handler should have been called")
}

func TestProviderDecorator_BlockAuthzWrappedMsgCreateConsumer(t *testing.T) {
app := helpers.Setup(t)
ctx := app.NewContext(false)
cdc := app.AppCodec()

decorator := ante.NewProviderDecorator(cdc)

// Create a mock MsgCreateConsumer
msgCreateConsumer := &providertypes.MsgCreateConsumer{
Submitter: "cosmos1abcdef1234567890abcdef1234567890abcdef",
}

// Wrap it in an authz MsgExec
anyMsg, err := codectypes.NewAnyWithValue(msgCreateConsumer)
require.NoError(t, err)

msgExec := &authz.MsgExec{
Grantee: "cosmos1fedcba0987654321fedcba0987654321fedcba",
Msgs: []*codectypes.Any{anyMsg},
}

// Create a transaction with the wrapped message
txBuilder := app.GetTxConfig().NewTxBuilder()
err = txBuilder.SetMsgs(msgExec)
require.NoError(t, err)
tx := txBuilder.GetTx()

// Test that the decorator blocks the wrapped MsgCreateConsumer
_, err = decorator.AnteHandle(ctx, tx, false, func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
require.Fail(t, "next handler should not be called")
return ctx, nil
})

require.Error(t, err)
require.Contains(t, err.Error(), "MsgCreateConsumer is disabled")
}
4 changes: 2 additions & 2 deletions tests/interchain/consumer_chain/changeover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ func (s *ChangeoverSuite) SetupSuite() {
s.Require().NoError(err)

s.Consumer = consumer

s.UpgradeChain()
}

func (s *ChangeoverSuite) TestRewardsWithChangeover() {
Expand All @@ -84,6 +82,8 @@ func (s *ChangeoverSuite) TestRewardsWithChangeover() {
s.changeSovereignToConsumer(s.Consumer, transferCh)
})

s.UpgradeChain()

s.Run("rewards", func() {
govAuthority, err := s.Chain.GetGovernanceAddress(s.GetContext())
s.Require().NoError(err)
Expand Down
15 changes: 0 additions & 15 deletions tests/interchain/consumer_chain/consumer_launch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,6 @@ func (s *ConsumerLaunchSuite) TestChainLaunch() {
jailed, err = s.Chain.IsValidatorJailedForConsumerDowntime(s.GetContext(), s.Relayer, consumer, 5)
s.Require().NoError(err)
s.Require().False(jailed, "validator 5 should not be jailed for downtime")

cfg.Version = s.OtherChainVersionPostUpgrade
cfg.Spec.ChainConfig.Images[0].Version = s.OtherChainVersionPostUpgrade
consumer2, err := s.Chain.AddConsumerChain(s.GetContext(), s.Relayer, cfg)
s.Require().NoError(err)
err = s.Chain.CheckCCV(s.GetContext(), consumer2, s.Relayer, 1_000_000, 0, 1)
s.Require().NoError(err)
s.Require().NoError(chainsuite.SendSimpleIBCTx(s.GetContext(), s.Chain, consumer2, s.Relayer))

jailed, err = s.Chain.IsValidatorJailedForConsumerDowntime(s.GetContext(), s.Relayer, consumer2, 1)
s.Require().NoError(err)
s.Require().True(jailed, "validator 1 should be jailed for downtime")
jailed, err = s.Chain.IsValidatorJailedForConsumerDowntime(s.GetContext(), s.Relayer, consumer2, 5)
s.Require().NoError(err)
s.Require().False(jailed, "validator 5 should not be jailed for downtime")
}

func selectConsumerVersion(preV21, postV21 string) string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func (s *ConsumerModificationSuite) TestChangeOwner() {
s.Require().NoError(err)
s.Require().NoError(s.Chain.CheckCCV(s.GetContext(), consumer, s.Relayer, 1_000_000, 0, 1))

s.UpgradeChain()

govAddress, err := s.Chain.GetGovernanceAddress(s.GetContext())
s.Require().NoError(err)
consumerID, err := s.Chain.GetConsumerID(s.GetContext(), consumer.Config().ChainID)
Expand Down Expand Up @@ -107,6 +109,8 @@ func (s *ConsumerModificationSuite) TestChangePowerShaping() {
s.Require().NoError(err)
s.Require().NoError(s.Chain.CheckCCV(s.GetContext(), consumer, s.Relayer, 1_000_000, 0, 1))

s.UpgradeChain()

consumerID, err := s.Chain.GetConsumerID(s.GetContext(), consumer.Config().ChainID)
s.Require().NoError(err)
update := &providertypes.MsgUpdateConsumer{
Expand Down Expand Up @@ -175,6 +179,8 @@ func (s *ConsumerModificationSuite) TestConsumerCommissionRate() {
s.Require().NoError(err)
s.Require().NoError(s.Chain.CheckCCV(s.GetContext(), consumer2, s.Relayer, 1_000_000, 0, 1))

s.UpgradeChain()

for i := 1; i < len(consumer1.Validators); i++ {
s.Require().NoError(consumer1.Validators[i].StopContainer(s.GetContext()))
s.Require().NoError(consumer2.Validators[i].StopContainer(s.GetContext()))
Expand Down Expand Up @@ -331,6 +337,8 @@ func (s *ConsumerModificationSuite) TestLaunchWithAllowListThenModify() {

s.Require().NoError(s.Chain.CheckCCV(s.GetContext(), consumer, s.Relayer, 1_000_000, 0, 1))

s.UpgradeChain()

consumerID, err := s.Chain.GetConsumerID(s.GetContext(), consumer.Config().ChainID)
s.Require().NoError(err)

Expand Down Expand Up @@ -378,7 +386,7 @@ func TestConsumerModification(t *testing.T) {
Suite: chainsuite.NewSuite(chainsuite.SuiteConfig{
CreateRelayer: true,
Scope: chainsuite.ChainScopeTest,
UpgradeOnSetup: true,
UpgradeOnSetup: false,
ChainSpec: &interchaintest.ChainSpec{
NumValidators: &chainsuite.SixValidators,
ChainConfig: ibc.ChainConfig{
Expand Down
Loading
Loading