Skip to content
Open
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
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
5 changes: 5 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 @@ -75,6 +75,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
48 changes: 48 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,54 @@ 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")
}

// TestConnOpenConfirm - chainB calls ConnOpenConfirm to confirm that
// chainA state is now OPEN.
func (suite *KeeperTestSuite) TestConnOpenConfirm() {
Expand Down
13 changes: 13 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,12 @@ 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")

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

// Keeper defines the IBC connection keeper
type Keeper struct {
// implements gRPC QueryServer interface
Expand Down Expand Up @@ -46,6 +52,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
}

// GetCommitmentPrefix returns the IBC connection store prefix as a commitment
// Prefix
func (k Keeper) GetCommitmentPrefix() exported.Prefix {
Expand Down
8 changes: 8 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,9 @@ 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")

// 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 Down Expand Up @@ -106,6 +109,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
43 changes: 43 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,49 @@ 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")
}

// 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
25 changes: 24 additions & 1 deletion sei-ibc-go/modules/core/04-channel/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/tendermint/tendermint/libs/log"
db "github.com/tendermint/tm-db"

Expand All @@ -29,6 +30,7 @@ type Keeper struct {

storeKey sdk.StoreKey
cdc codec.BinaryCodec
paramSpace paramtypes.Subspace
clientKeeper types.ClientKeeper
connectionKeeper types.ConnectionKeeper
portKeeper types.PortKeeper
Expand All @@ -37,20 +39,41 @@ type Keeper struct {

// NewKeeper creates a new IBC channel Keeper instance
func NewKeeper(
cdc codec.BinaryCodec, key sdk.StoreKey,
cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace,
clientKeeper types.ClientKeeper, connectionKeeper types.ConnectionKeeper,
portKeeper types.PortKeeper, scopedKeeper capabilitykeeper.ScopedKeeper,
) Keeper {
return Keeper{
storeKey: key,
cdc: cdc,
paramSpace: paramSpace,
clientKeeper: clientKeeper,
connectionKeeper: connectionKeeper,
portKeeper: portKeeper,
scopedKeeper: scopedKeeper,
}
}

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

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

// 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
}

// 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
}

// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+host.ModuleName+"/"+types.SubModuleName)
Expand Down
16 changes: 16 additions & 0 deletions sei-ibc-go/modules/core/04-channel/keeper/packet.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"
)

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

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

// SendPacket is called by a module in order to send an IBC packet on a channel
// end owned by the calling module to the corresponding module on the counterparty
// chain.
Expand All @@ -23,6 +29,11 @@ func (k Keeper) SendPacket(
channelCap *capabilitytypes.Capability,
packet exported.PacketI,
) error {
// outbound gating: disallow sending packets when outbound disabled
if !k.IsOutboundEnabled(ctx) {
return sdkerrors.Wrap(ErrOutboundDisabled, "ibc outbound disabled")
}

if err := packet.ValidateBasic(); err != nil {
return sdkerrors.Wrap(err, "packet failed basic validation")
}
Expand Down Expand Up @@ -157,6 +168,11 @@ func (k Keeper) RecvPacket(
proof []byte,
proofHeight exported.Height,
) error {
// inbound gating: disallow processing inbound packets when inbound disabled
if !k.IsInboundEnabled(ctx) {
return sdkerrors.Wrap(ErrInboundDisabled, "ibc inbound disabled")
}

channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel())
if !found {
return sdkerrors.Wrap(types.ErrChannelNotFound, packet.GetDestChannel())
Expand Down
40 changes: 40 additions & 0 deletions sei-ibc-go/modules/core/04-channel/keeper/packet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,46 @@ func (suite *KeeperTestSuite) TestRecvPacket() {
}
}

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

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

// prepare packet from A -> B
packet := types.NewPacket(ibctesting.MockPacketData, 1,
path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID,
path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID,
timeoutHeight, disabledTimeoutTimestamp,
)

err := path.EndpointA.SendPacket(packet)
suite.Require().NoError(err)

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

// get proof of packet commitment from chainA
packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
proof, proofHeight := path.EndpointA.QueryProof(packetKey)

channelCap := suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)

// attempt RecvPacket with inbound disabled
err = suite.chainB.App.GetIBCKeeper().ChannelKeeper.RecvPacket(
suite.chainB.GetContext(), channelCap, packet, proof, proofHeight,
)

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

func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
var (
path *ibctesting.Path
Expand Down
3 changes: 3 additions & 0 deletions sei-ibc-go/modules/core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import (
// InitGenesis initializes the ibc state from a provided genesis
// state.
func InitGenesis(ctx sdk.Context, k keeper.Keeper, createLocalhost bool, gs *types.GenesisState) {
// Initialize core params with defaults if not set
k.SetParams(ctx, types.DefaultParams())

client.InitGenesis(ctx, k.ClientKeeper, gs.ClientGenesis)
connection.InitGenesis(ctx, k.ConnectionKeeper, gs.ConnectionGenesis)
channel.InitGenesis(ctx, k.ChannelKeeper, gs.ChannelGenesis)
Expand Down
Loading
Loading