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
13 changes: 13 additions & 0 deletions app/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ func (app *App) RegisterUpgradeHandlers() {
return newVM, err
}

// IBC Toggle migration: initialize InboundEnabled and OutboundEnabled params
if upgradeName == "v6.4.0" {
newVM, err := app.mm.RunMigrations(ctx, app.configurator, fromVM)
if err != nil {
return newVM, err
}

// Enable IBC inbound and outbound by default
app.IBCKeeper.SetInboundEnabled(ctx, true)
app.IBCKeeper.SetOutboundEnabled(ctx, true)
return newVM, err
}

return app.mm.RunMigrations(ctx, app.configurator, fromVM)
})
}
Expand Down
8 changes: 8 additions & 0 deletions sei-ibc-go/modules/core/02-client/keeper/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,19 @@ import (
"github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/exported"
)

// ErrInboundDisabled is the error for when inbound is disabled
var ErrInboundDisabled = sdkerrors.Register("ibc-client", 101, "ibc inbound disabled")

// CreateClient creates a new client state and populates it with a given consensus
// state as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-002-client-semantics#create
func (k Keeper) CreateClient(
ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState,
) (string, error) {
// inbound gating: disallow client creation as part of inbound handshakes when inbound disabled
if !k.IsInboundEnabled(ctx) {
return "", sdkerrors.Wrap(ErrInboundDisabled, "client creation inbound disabled")
}

params := k.GetParams(ctx)
if !params.IsAllowedClient(clientState.ClientType()) {
return "", sdkerrors.Wrapf(
Expand Down
21 changes: 21 additions & 0 deletions sei-ibc-go/modules/core/02-client/keeper/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ func (suite *KeeperTestSuite) TestCreateClient() {
}
}

// TestCreateClient_BlockedWhenInboundDisabled tests that CreateClient
// is blocked when inbound IBC is disabled.
func (suite *KeeperTestSuite) TestCreateClient_BlockedWhenInboundDisabled() {
// disable inbound on chainA
ibcKeeperA := suite.chainA.App.GetIBCKeeper()
ibcKeeperA.SetInboundEnabled(suite.chainA.GetContext(), false)
suite.Require().False(ibcKeeperA.IsInboundEnabled(suite.chainA.GetContext()))

clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)

// attempt CreateClient with inbound disabled
clientID, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.CreateClient(
suite.chainA.GetContext(), clientState, suite.consensusState,
)

// should fail with ErrInboundDisabled
suite.Require().Error(err)
suite.Require().Contains(err.Error(), "inbound")
suite.Require().Equal("", clientID)
}

func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
var (
path *ibctesting.Path
Expand Down
10 changes: 10 additions & 0 deletions sei-ibc-go/modules/core/02-client/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import (
ibctmtypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/light-clients/07-tendermint/types"
)

// KeyInboundEnabled is the param key for inbound enabled
var KeyInboundEnabled = []byte("InboundEnabled")

// Keeper represents a type that grants read and write permissions to any client
// state information
type Keeper struct {
Expand Down Expand Up @@ -53,6 +56,13 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+host.ModuleName+"/"+types.SubModuleName)
}

// IsInboundEnabled returns true if inbound IBC is enabled.
func (k Keeper) IsInboundEnabled(ctx sdk.Context) bool {
var inbound bool
k.paramSpace.Get(ctx, KeyInboundEnabled, &inbound)
return inbound
}

// GenerateClientIdentifier returns the next client identifier.
func (k Keeper) GenerateClientIdentifier(ctx sdk.Context, clientType string) string {
nextClientSeq := k.GetNextClientSequence(ctx)
Expand Down
10 changes: 10 additions & 0 deletions sei-ibc-go/modules/core/03-connection/keeper/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ func (k Keeper) ConnOpenInit(
version *types.Version,
delayPeriod uint64,
) (string, error) {
// outbound gating: disallow outbound connection inits when outbound disabled
if !k.IsOutboundEnabled(ctx) {
return "", sdkerrors.Wrap(ErrOutboundDisabled, "connection outbound disabled")
}

versions := types.GetCompatibleVersions()
if version != nil {
if !types.IsSupportedVersion(version) {
Expand Down Expand Up @@ -75,6 +80,11 @@ func (k Keeper) ConnOpenTry(
proofHeight exported.Height, // height at which relayer constructs proof of A storing connectionEnd in state
consensusHeight exported.Height, // latest height of chain B which chain A has stored in its chain B client
) (string, error) {
// inbound gating: disallow inbound connection tries when inbound disabled
if !k.IsInboundEnabled(ctx) {
return "", sdkerrors.Wrap(ErrInboundDisabled, "connection inbound disabled")
}

var (
connectionID string
previousConnection types.ConnectionEnd
Expand Down
73 changes: 73 additions & 0 deletions sei-ibc-go/modules/core/03-connection/keeper/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,79 @@ func (suite *KeeperTestSuite) TestConnOpenAck() {
}
}

// TestConnOpenTry_BlockedWhenInboundDisabled tests that ConnOpenTry
// is blocked when inbound IBC is disabled.
func (suite *KeeperTestSuite) TestConnOpenTry_BlockedWhenInboundDisabled() {
suite.SetupTest()

path := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupClients(path)

// chainA initiates connection
err := path.EndpointA.ConnOpenInit()
suite.Require().NoError(err)

// retrieve client state of chainA to pass as counterpartyClient
counterpartyClient := suite.chainA.GetClientState(path.EndpointA.ClientID)

// disable inbound on chainB
ibcKeeperB := suite.chainB.App.GetIBCKeeper()
ibcKeeperB.SetInboundEnabled(suite.chainB.GetContext(), false)
suite.Require().False(ibcKeeperB.IsInboundEnabled(suite.chainB.GetContext()))

// ensure client is up to date on chainB
err = path.EndpointB.UpdateClient()
suite.Require().NoError(err)

counterparty := types.NewCounterparty(path.EndpointA.ClientID, path.EndpointA.ConnectionID, suite.chainA.GetPrefix())

connectionKey := host.ConnectionKey(path.EndpointA.ConnectionID)
proofInit, proofHeight := suite.chainA.QueryProof(connectionKey)

consensusHeight := counterpartyClient.GetLatestHeight()
consensusKey := host.FullConsensusStateKey(path.EndpointA.ClientID, consensusHeight)
proofConsensus, _ := suite.chainA.QueryProof(consensusKey)

clientKey := host.FullClientStateKey(path.EndpointA.ClientID)
proofClient, _ := suite.chainA.QueryProof(clientKey)

// attempt ConnOpenTry on chainB with inbound disabled
_, err = suite.chainB.App.GetIBCKeeper().ConnectionKeeper.ConnOpenTry(
suite.chainB.GetContext(), "", counterparty, 0, path.EndpointB.ClientID, counterpartyClient,
types.GetCompatibleVersions(), proofInit, proofClient, proofConsensus,
proofHeight, consensusHeight,
)

// should fail with ErrInboundDisabled
suite.Require().Error(err)
suite.Require().Contains(err.Error(), "inbound")
}

// TestConnOpenInit_BlockedWhenOutboundDisabled tests that ConnOpenInit
// is blocked when outbound IBC is disabled.
func (suite *KeeperTestSuite) TestConnOpenInit_BlockedWhenOutboundDisabled() {
suite.SetupTest()

path := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupClients(path)

// disable outbound on chainA
ibcKeeperA := suite.chainA.App.GetIBCKeeper()
ibcKeeperA.SetOutboundEnabled(suite.chainA.GetContext(), false)
suite.Require().False(ibcKeeperA.IsOutboundEnabled(suite.chainA.GetContext()))

counterparty := types.NewCounterparty(path.EndpointB.ClientID, "", suite.chainB.GetPrefix())

// attempt ConnOpenInit on chainA with outbound disabled
_, err := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.ConnOpenInit(
suite.chainA.GetContext(), path.EndpointA.ClientID, counterparty, types.DefaultIBCVersion, 0,
)

// should fail with ErrOutboundDisabled
suite.Require().Error(err)
suite.Require().Contains(err.Error(), "outbound")
}

// TestConnOpenConfirm - chainB calls ConnOpenConfirm to confirm that
// chainA state is now OPEN.
func (suite *KeeperTestSuite) TestConnOpenConfirm() {
Expand Down
26 changes: 26 additions & 0 deletions sei-ibc-go/modules/core/03-connection/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ import (
"github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/exported"
)

// KeyInboundEnabled is the param key for inbound enabled
var KeyInboundEnabled = []byte("InboundEnabled")

// KeyOutboundEnabled is the param key for outbound enabled
var KeyOutboundEnabled = []byte("OutboundEnabled")

// ErrInboundDisabled is the error for when inbound is disabled
var ErrInboundDisabled = sdkerrors.Register("ibc-connection", 101, "ibc inbound disabled")

// ErrOutboundDisabled is the error for when outbound is disabled
var ErrOutboundDisabled = sdkerrors.Register("ibc-connection", 102, "ibc outbound disabled")

// Keeper defines the IBC connection keeper
type Keeper struct {
// implements gRPC QueryServer interface
Expand Down Expand Up @@ -46,6 +58,20 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+host.ModuleName+"/"+types.SubModuleName)
}

// IsInboundEnabled returns true if inbound IBC is enabled.
func (k Keeper) IsInboundEnabled(ctx sdk.Context) bool {
var inbound bool
k.paramSpace.Get(ctx, KeyInboundEnabled, &inbound)
return inbound
}

// IsOutboundEnabled returns true if outbound IBC is enabled.
func (k Keeper) IsOutboundEnabled(ctx sdk.Context) bool {
var outbound bool
k.paramSpace.Get(ctx, KeyOutboundEnabled, &outbound)
return outbound
}

// GetCommitmentPrefix returns the IBC connection store prefix as a commitment
// Prefix
func (k Keeper) GetCommitmentPrefix() exported.Prefix {
Expand Down
16 changes: 16 additions & 0 deletions sei-ibc-go/modules/core/04-channel/keeper/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ import (
"github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/exported"
)

// ErrInboundDisabledHandshake is the error for when inbound is disabled during channel handshake
var ErrInboundDisabledHandshake = sdkerrors.Register("ibc-channel-handshake", 101, "ibc inbound disabled")

// ErrOutboundDisabledHandshake is the error for when outbound is disabled during channel handshake
var ErrOutboundDisabledHandshake = sdkerrors.Register("ibc-channel-handshake", 102, "ibc outbound disabled")

// ChanOpenInit is called by a module to initiate a channel opening handshake with
// a module on another chain. The counterparty channel identifier is validated to be
// empty in msg validation.
Expand All @@ -27,6 +33,11 @@ func (k Keeper) ChanOpenInit(
counterparty types.Counterparty,
version string,
) (string, *capabilitytypes.Capability, error) {
// outbound gating: disallow outbound channel inits when outbound disabled
if !k.IsOutboundEnabled(ctx) {
return "", nil, sdkerrors.Wrap(ErrOutboundDisabledHandshake, "channel outbound disabled")
}

// connection hop length checked on msg.ValidateBasic()
connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0])
if !found {
Expand Down Expand Up @@ -106,6 +117,11 @@ func (k Keeper) ChanOpenTry(
proofInit []byte,
proofHeight exported.Height,
) (string, *capabilitytypes.Capability, error) {
// inbound gating: disallow inbound channel tries when inbound disabled
if !k.IsInboundEnabled(ctx) {
return "", nil, sdkerrors.Wrap(ErrInboundDisabledHandshake, "channel inbound disabled")
}

var (
previousChannel types.Channel
previousChannelFound bool
Expand Down
74 changes: 74 additions & 0 deletions sei-ibc-go/modules/core/04-channel/keeper/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,80 @@ func (suite *KeeperTestSuite) TestChanOpenTry() {
}
}

// TestChanOpenTry_BlockedWhenInboundDisabled tests that ChanOpenTry
// is blocked when inbound IBC is disabled.
func (suite *KeeperTestSuite) TestChanOpenTry_BlockedWhenInboundDisabled() {
suite.SetupTest()

path := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
path.SetChannelOrdered()

// chainA opens channel
err := path.EndpointA.ChanOpenInit()
suite.Require().NoError(err)

// create port capability on chainB
suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
portCap := suite.chainB.GetPortCapability(ibctesting.MockPort)

// disable inbound on chainB
ibcKeeperB := suite.chainB.App.GetIBCKeeper()
ibcKeeperB.SetInboundEnabled(suite.chainB.GetContext(), false)
suite.Require().False(ibcKeeperB.IsInboundEnabled(suite.chainB.GetContext()))

// ensure client is up to date on chainB
err = path.EndpointB.UpdateClient()
suite.Require().NoError(err)

counterparty := types.NewCounterparty(path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID)

channelKey := host.ChannelKey(counterparty.PortId, counterparty.ChannelId)
proof, proofHeight := suite.chainA.QueryProof(channelKey)

// attempt ChanOpenTry on chainB with inbound disabled
_, _, err = suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanOpenTry(
suite.chainB.GetContext(), types.ORDERED, []string{path.EndpointB.ConnectionID},
path.EndpointB.ChannelConfig.PortID, "", portCap, counterparty, path.EndpointA.ChannelConfig.Version,
proof, proofHeight,
)

// should fail with ErrInboundDisabled
suite.Require().Error(err)
suite.Require().Contains(err.Error(), "inbound")
}

// TestChanOpenInit_BlockedWhenOutboundDisabled tests that ChanOpenInit
// is blocked when outbound IBC is disabled.
func (suite *KeeperTestSuite) TestChanOpenInit_BlockedWhenOutboundDisabled() {
suite.SetupTest()

path := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
path.SetChannelOrdered()

// create port capability on chainA
suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
portCap := suite.chainA.GetPortCapability(ibctesting.MockPort)

// disable outbound on chainA
ibcKeeperA := suite.chainA.App.GetIBCKeeper()
ibcKeeperA.SetOutboundEnabled(suite.chainA.GetContext(), false)
suite.Require().False(ibcKeeperA.IsOutboundEnabled(suite.chainA.GetContext()))

counterparty := types.NewCounterparty(ibctesting.MockPort, "")

// attempt ChanOpenInit on chainA with outbound disabled
_, _, err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.ChanOpenInit(
suite.chainA.GetContext(), types.ORDERED, []string{path.EndpointA.ConnectionID},
path.EndpointA.ChannelConfig.PortID, portCap, counterparty, path.EndpointA.ChannelConfig.Version,
)

// should fail with ErrOutboundDisabled
suite.Require().Error(err)
suite.Require().Contains(err.Error(), "outbound")
}

// TestChanOpenAck tests the OpenAck handshake call for channels. It uses message passing
// to enter into the appropriate state and then calls ChanOpenAck directly. The handshake
// call is occurring on chainA.
Expand Down
Loading
Loading