From b1211ea5c335ddb33abc72c5efa8522e3d9bd523 Mon Sep 17 00:00:00 2001 From: mpoke Date: Mon, 29 Aug 2022 19:18:07 +0200 Subject: [PATCH] move IBC handlers to ibc-module.go --- x/ccv/consumer/ibc_module.go | 277 ++++++++++++++++++++++++++++++++++ x/ccv/consumer/module.go | 284 +---------------------------------- x/ccv/provider/ibc_module.go | 248 ++++++++++++++++++++++++++++++ x/ccv/provider/module.go | 263 ++------------------------------ 4 files changed, 543 insertions(+), 529 deletions(-) create mode 100644 x/ccv/consumer/ibc_module.go create mode 100644 x/ccv/provider/ibc_module.go diff --git a/x/ccv/consumer/ibc_module.go b/x/ccv/consumer/ibc_module.go new file mode 100644 index 0000000000..23666c325f --- /dev/null +++ b/x/ccv/consumer/ibc_module.go @@ -0,0 +1,277 @@ +package consumer + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/interchain-security/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" + providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/x/ccv/types" +) + +// OnChanOpenInit implements the IBCModule interface +// this function is called by the relayer. +func (am AppModule) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + // ensure provider channel hasn't already been created + if providerChannel, ok := am.keeper.GetProviderChannel(ctx); ok { + return sdkerrors.Wrapf(ccv.ErrDuplicateChannel, + "provider channel: %s already set", providerChannel) + } + + if err := validateCCVChannelParams( + ctx, am.keeper, order, portID, version, + ); err != nil { + return err + } + + // Claim channel capability passed back by IBC module + if err := am.keeper.ClaimCapability( + ctx, chanCap, host.ChannelCapabilityPath(portID, channelID), + ); err != nil { + return err + } + + return am.keeper.VerifyProviderChain(ctx, channelID, connectionHops) +} + +// validateCCVChannelParams validates a ccv channel +func validateCCVChannelParams( + ctx sdk.Context, + keeper keeper.Keeper, + order channeltypes.Order, + portID string, + version string, +) error { + if order != channeltypes.ORDERED { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.ORDERED, order) + } + + // Require portID is the portID CCV module is bound to + boundPort := keeper.GetPort(ctx) + if boundPort != portID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort) + } + + if version != ccv.Version { + return sdkerrors.Wrapf(ccv.ErrInvalidVersion, "got %s, expected %s", version, ccv.Version) + } + return nil +} + +// OnChanOpenTry implements the IBCModule interface +func (am AppModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + return "", sdkerrors.Wrap(ccv.ErrInvalidChannelFlow, "channel handshake must be initiated by consumer chain") +} + +// OnChanOpenAck implements the IBCModule interface +func (am AppModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelID string, + counterpartyMetadata string, +) error { + // ensure provider channel has already been created + if providerChannel, ok := am.keeper.GetProviderChannel(ctx); ok { + return sdkerrors.Wrapf(ccv.ErrDuplicateChannel, + "provider channel: %s already established", providerChannel) + } + + var md providertypes.HandshakeMetadata + if err := (&md).Unmarshal([]byte(counterpartyMetadata)); err != nil { + return sdkerrors.Wrapf(ccv.ErrInvalidHandshakeMetadata, + "error unmarshalling ibc-ack metadata: \n%v; \nmetadata: %v", err, counterpartyMetadata) + } + + if md.Version != ccv.Version { + return sdkerrors.Wrapf(ccv.ErrInvalidVersion, + "invalid counterparty version: %s, expected %s", md.Version, ccv.Version) + } + + am.keeper.SetProviderFeePoolAddrStr(ctx, md.ProviderFeePoolAddr) + + /////////////////////////////////////////////////// + // Initialize distribution token transfer channel + // + // NOTE The handshake for this channel is handled by the ibc-go/transfer + // module. If the transfer-channel fails here (unlikely) then the transfer + // channel should be manually created and ccv parameters set accordingly. + + // reuse the connection hops for this channel for the + // transfer channel being created. + connHops, err := am.keeper.GetConnectionHops(ctx, portID, channelID) + if err != nil { + return err + } + + distrTransferMsg := channeltypes.NewMsgChannelOpenInit( + transfertypes.PortID, + transfertypes.Version, + channeltypes.UNORDERED, + connHops, + transfertypes.PortID, + "", // signer unused + ) + + resp, err := am.keeper.ChannelOpenInit(ctx, distrTransferMsg) + if err != nil { + return err + } + am.keeper.SetDistributionTransmissionChannel(ctx, resp.ChannelId) + + return nil +} + +// OnChanOpenConfirm implements the IBCModule interface +func (am AppModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return sdkerrors.Wrap(ccv.ErrInvalidChannelFlow, "channel handshake must be initiated by consumer chain") +} + +// OnChanCloseInit implements the IBCModule interface +func (am AppModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // allow relayers to close duplicate OPEN channels, if the provider channel has already been established + if providerChannel, ok := am.keeper.GetProviderChannel(ctx); ok && providerChannel != channelID { + return nil + } + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") +} + +// OnChanCloseConfirm implements the IBCModule interface +func (am AppModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +// OnRecvPacket implements the IBCModule interface. A successful acknowledgement +// is returned if the packet data is successfully decoded and the receive application +// logic returns without error. +func (am AppModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) ibcexported.Acknowledgement { + var ( + ack ibcexported.Acknowledgement + data ccv.ValidatorSetChangePacketData + ) + if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + errAck := channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal CCV packet data: %s", err.Error())) + ack = &errAck + } else { + ack = am.keeper.OnRecvVSCPacket(ctx, packet, data) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeyModule, consumertypes.ModuleName), + sdk.NewAttribute(ccv.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack != nil)), + ), + ) + + return ack +} + +// OnAcknowledgementPacket implements the IBCModule interface +func (am AppModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + _ sdk.AccAddress, +) error { + var ack channeltypes.Acknowledgement + if err := ccv.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal consumer packet acknowledgement: %v", err) + } + + if err := am.keeper.OnAcknowledgementPacket(ctx, packet, ack); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeyModule, consumertypes.ModuleName), + sdk.NewAttribute(ccv.AttributeKeyAck, ack.String()), + ), + ) + switch resp := ack.Response.(type) { + case *channeltypes.Acknowledgement_Result: + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypePacket, + sdk.NewAttribute(ccv.AttributeKeyAckSuccess, string(resp.Result)), + ), + ) + case *channeltypes.Acknowledgement_Error: + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypePacket, + sdk.NewAttribute(ccv.AttributeKeyAckError, resp.Error), + ), + ) + } + return nil +} + +// OnTimeoutPacket implements the IBCModule interface +func (am AppModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) error { + var data ccv.SlashPacketData + if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal consumer packet data: %s", err.Error()) + } + + if err := am.keeper.OnTimeoutPacket(ctx, packet, data); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypeTimeout, + sdk.NewAttribute(sdk.AttributeKeyModule, consumertypes.ModuleName), + ), + ) + + return nil +} diff --git a/x/ccv/consumer/module.go b/x/ccv/consumer/module.go index fd9ea4498d..8868061036 100644 --- a/x/ccv/consumer/module.go +++ b/x/ccv/consumer/module.go @@ -14,21 +14,13 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" "github.com/cosmos/interchain-security/x/ccv/consumer/keeper" - "github.com/cosmos/interchain-security/x/ccv/consumer/types" - providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/x/ccv/types" + consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" ) var ( @@ -42,7 +34,7 @@ type AppModuleBasic struct{} // Name implements AppModuleBasic interface func (AppModuleBasic) Name() string { - return types.ModuleName + return consumertypes.ModuleName } // RegisterLegacyAminoCodec implements AppModuleBasic interface @@ -58,14 +50,14 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) // DefaultGenesis returns default genesis state as raw bytes for the ibc // consumer module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return cdc.MustMarshalJSON(types.DefaultGenesisState()) + return cdc.MustMarshalJSON(consumertypes.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the ibc consumer module. func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - var data types.GenesisState + var data consumertypes.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { - return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + return fmt.Errorf("failed to unmarshal %s genesis state: %w", consumertypes.ModuleName, err) } return data.Validate() @@ -118,7 +110,7 @@ func (am AppModule) Route() sdk.Route { // QuerierRoute implements the AppModule interface func (AppModule) QuerierRoute() string { - return types.QuerierRoute + return consumertypes.QuerierRoute } // LegacyQuerierHandler implements the AppModule interface @@ -134,7 +126,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the consumer module. It returns // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { - var genesisState types.GenesisState + var genesisState consumertypes.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) return am.keeper.InitGenesis(ctx, &genesisState) } @@ -225,265 +217,3 @@ func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { return nil } - -// ValidateConsumerChannelParams does validation of a newly created ccv channel. A consumer -// channel must be ORDERED, use the correct port (by default 'consumer' on this module), and use the current -// supported version. -func ValidateConsumerChannelParams( - ctx sdk.Context, - keeper keeper.Keeper, - order channeltypes.Order, - portID string, - channelID string, - version string, -) error { - if order != channeltypes.ORDERED { - return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.ORDERED, order) - } - - // Require portID is the portID CCV module is bound to - boundPort := keeper.GetPort(ctx) - if boundPort != portID { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort) - } - - if version != ccv.Version { - return sdkerrors.Wrapf(ccv.ErrInvalidVersion, "got %s, expected %s", version, ccv.Version) - } - return nil -} - -// OnChanOpenInit implements the IBCModule interface -// this function is called by the relayer. -func (am AppModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) error { - // ensure provider channel hasn't already been created - if providerChannel, ok := am.keeper.GetProviderChannel(ctx); ok { - return sdkerrors.Wrapf(ccv.ErrDuplicateChannel, - "provider channel: %s already set", providerChannel) - } - - if err := ValidateConsumerChannelParams( - ctx, am.keeper, order, portID, channelID, version, - ); err != nil { - return err - } - - // Claim channel capability passed back by IBC module - if err := am.keeper.ClaimCapability( - ctx, chanCap, host.ChannelCapabilityPath(portID, channelID), - ); err != nil { - return err - } - - return am.keeper.VerifyProviderChain(ctx, channelID, connectionHops) -} - -// OnChanOpenTry implements the IBCModule interface -func (am AppModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - return "", sdkerrors.Wrap(ccv.ErrInvalidChannelFlow, "channel handshake must be initiated by consumer chain") -} - -// OnChanOpenAck implements the IBCModule interface -func (am AppModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyChannelID string, - counterpartyMetadata string, -) error { - // ensure provider channel has already been created - if providerChannel, ok := am.keeper.GetProviderChannel(ctx); ok { - return sdkerrors.Wrapf(ccv.ErrDuplicateChannel, - "provider channel: %s already established", providerChannel) - } - - var md providertypes.HandshakeMetadata - if err := (&md).Unmarshal([]byte(counterpartyMetadata)); err != nil { - return sdkerrors.Wrapf(ccv.ErrInvalidHandshakeMetadata, - "error unmarshalling ibc-ack metadata: \n%v; \nmetadata: %v", err, counterpartyMetadata) - } - - if md.Version != ccv.Version { - return sdkerrors.Wrapf(ccv.ErrInvalidVersion, - "invalid counterparty version: %s, expected %s", md.Version, ccv.Version) - } - - am.keeper.SetProviderFeePoolAddrStr(ctx, md.ProviderFeePoolAddr) - - /////////////////////////////////////////////////// - // Initialize distribution token transfer channel - // - // NOTE The handshake for this channel is handled by the ibc-go/transfer - // module. If the transfer-channel fails here (unlikely) then the transfer - // channel should be manually created and ccv parameters set accordingly. - - // reuse the connection hops for this channel for the - // transfer channel being created. - connHops, err := am.keeper.GetConnectionHops(ctx, portID, channelID) - if err != nil { - return err - } - - distrTransferMsg := channeltypes.NewMsgChannelOpenInit( - transfertypes.PortID, - transfertypes.Version, - channeltypes.UNORDERED, - connHops, - transfertypes.PortID, - "", // signer unused - ) - - resp, err := am.keeper.ChannelOpenInit(ctx, distrTransferMsg) - if err != nil { - return err - } - am.keeper.SetDistributionTransmissionChannel(ctx, resp.ChannelId) - - return nil -} - -// OnChanOpenConfirm implements the IBCModule interface -func (am AppModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - return sdkerrors.Wrap(ccv.ErrInvalidChannelFlow, "channel handshake must be initiated by consumer chain") -} - -// OnChanCloseInit implements the IBCModule interface -func (am AppModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // allow relayers to close duplicate OPEN channels, if the provider channel has already been established - if providerChannel, ok := am.keeper.GetProviderChannel(ctx); ok && providerChannel != channelID { - return nil - } - return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") -} - -// OnChanCloseConfirm implements the IBCModule interface -func (am AppModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - return nil -} - -// OnRecvPacket implements the IBCModule interface. A successful acknowledgement -// is returned if the packet data is successfully decoded and the receive application -// logic returns without error. -func (am AppModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - _ sdk.AccAddress, -) ibcexported.Acknowledgement { - var ( - ack ibcexported.Acknowledgement - data ccv.ValidatorSetChangePacketData - ) - if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - errAck := channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal CCV packet data: %s", err.Error())) - ack = &errAck - } else { - ack = am.keeper.OnRecvVSCPacket(ctx, packet, data) - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(ccv.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack != nil)), - ), - ) - - return ack -} - -// OnAcknowledgementPacket implements the IBCModule interface -func (am AppModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - _ sdk.AccAddress, -) error { - var ack channeltypes.Acknowledgement - if err := ccv.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal consumer packet acknowledgement: %v", err) - } - - if err := am.keeper.OnAcknowledgementPacket(ctx, packet, ack); err != nil { - return err - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(ccv.AttributeKeyAck, ack.String()), - ), - ) - switch resp := ack.Response.(type) { - case *channeltypes.Acknowledgement_Result: - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypePacket, - sdk.NewAttribute(ccv.AttributeKeyAckSuccess, string(resp.Result)), - ), - ) - case *channeltypes.Acknowledgement_Error: - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypePacket, - sdk.NewAttribute(ccv.AttributeKeyAckError, resp.Error), - ), - ) - } - return nil -} - -// OnTimeoutPacket implements the IBCModule interface -func (am AppModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - _ sdk.AccAddress, -) error { - var data ccv.SlashPacketData - if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal consumer packet data: %s", err.Error()) - } - - if err := am.keeper.OnTimeoutPacket(ctx, packet, data); err != nil { - return err - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypeTimeout, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - ) - - return nil -} diff --git a/x/ccv/provider/ibc_module.go b/x/ccv/provider/ibc_module.go new file mode 100644 index 0000000000..a34331db9e --- /dev/null +++ b/x/ccv/provider/ibc_module.go @@ -0,0 +1,248 @@ +package provider + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/interchain-security/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" + ccv "github.com/cosmos/interchain-security/x/ccv/types" +) + +// OnChanOpenInit implements the IBCModule interface +func (am AppModule) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + return sdkerrors.Wrap(ccv.ErrInvalidChannelFlow, "channel handshake must be initiated by consumer chain") +} + +// OnChanOpenTry implements the IBCModule interface +func (am AppModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (metadata string, err error) { + if err := validateCCVChannelParams( + ctx, am.keeper, order, portID, + ); err != nil { + return "", err + } + + if counterpartyVersion != ccv.Version { + return "", sdkerrors.Wrapf( + ccv.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", + counterpartyVersion, ccv.Version) + } + + // Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos + // (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry) + // If module can already authenticate the capability then module already owns it so we don't need to claim + // Otherwise, module does not have channel capability and we must claim it from IBC + if !am.keeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { + // Only claim channel capability passed back by IBC module if we do not already own it + if err := am.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err + } + } + + if err := am.keeper.VerifyConsumerChain( + ctx, channelID, connectionHops, + ); err != nil { + return "", err + } + + md := providertypes.HandshakeMetadata{ + // NOTE that the fee pool collector address string provided to the + // the consumer chain must be excluded from the blocked addresses + // blacklist or all all ibc-transfers from the consumer chain to the + // provider chain will fail + ProviderFeePoolAddr: am.keeper.GetFeeCollectorAddressStr(ctx), + Version: ccv.Version, + } + mdBz, err := (&md).Marshal() + if err != nil { + return "", sdkerrors.Wrapf(ccv.ErrInvalidHandshakeMetadata, + "error marshalling ibc-try metadata: %v", err) + } + return string(mdBz), nil +} + +// validateCCVChannelParams validates a ccv channel +func validateCCVChannelParams( + ctx sdk.Context, + keeper *keeper.Keeper, + order channeltypes.Order, + portID string, +) error { + if order != channeltypes.ORDERED { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.ORDERED, order) + } + + // Require portID is the portID CCV module is bound to + boundPort := keeper.GetPort(ctx) + if boundPort != portID { + return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort) + } + return nil +} + +// OnChanOpenAck implements the IBCModule interface +func (am AppModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelID string, + counterpartyVersion string, +) error { + return sdkerrors.Wrap(ccv.ErrInvalidChannelFlow, "channel handshake must be initiated by consumer chain") +} + +// OnChanOpenConfirm implements the IBCModule interface +func (am AppModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + err := am.keeper.SetConsumerChain(ctx, channelID) + if err != nil { + return err + } + return nil +} + +// OnChanCloseInit implements the IBCModule interface +func (am AppModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // Disallow user-initiated channel closing for provider channels + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") +} + +// OnChanCloseConfirm implements the IBCModule interface +func (am AppModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +// OnRecvPacket implements the IBCModule interface. A successful acknowledgement +// is returned if the packet data is succesfully decoded and the receive application +// logic returns without error. +func (am AppModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) ibcexported.Acknowledgement { + var ( + ack ibcexported.Acknowledgement + vscMaturedData ccv.VSCMaturedPacketData + slashData ccv.SlashPacketData + ) + if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &vscMaturedData); err == nil { + // handle VSCMaturedPacket + ack = am.keeper.OnRecvVSCMaturedPacket(ctx, packet, vscMaturedData) + } else if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &slashData); err == nil { + // handle SlashPacket + ack = am.keeper.OnRecvSlashPacket(ctx, packet, slashData) + } else { + errAck := channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal CCV packet data: %s", err.Error())) + ack = &errAck + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeyModule, providertypes.ModuleName), + sdk.NewAttribute(ccv.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack != nil)), + ), + ) + + return ack +} + +// OnAcknowledgementPacket implements the IBCModule interface +func (am AppModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + _ sdk.AccAddress, +) error { + var ack channeltypes.Acknowledgement + if err := ccv.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal provider packet acknowledgement: %v", err) + } + + if err := am.keeper.OnAcknowledgementPacket(ctx, packet, ack); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeyModule, providertypes.ModuleName), + sdk.NewAttribute(ccv.AttributeKeyAck, ack.String()), + ), + ) + + switch resp := ack.Response.(type) { + case *channeltypes.Acknowledgement_Result: + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypePacket, + sdk.NewAttribute(ccv.AttributeKeyAckSuccess, string(resp.Result)), + ), + ) + case *channeltypes.Acknowledgement_Error: + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypePacket, + sdk.NewAttribute(ccv.AttributeKeyAckError, resp.Error), + ), + ) + } + + return nil +} + +// OnTimeoutPacket implements the IBCModule interface +func (am AppModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + _ sdk.AccAddress, +) error { + + if err := am.keeper.OnTimeoutPacket(ctx, packet); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + ccv.EventTypeTimeout, + sdk.NewAttribute(sdk.AttributeKeyModule, providertypes.ModuleName), + ), + ) + + return nil +} diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index 4597f4ba5d..39f11b850f 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -10,23 +10,17 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" "github.com/cosmos/interchain-security/x/ccv/provider/client/cli" "github.com/cosmos/interchain-security/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/x/ccv/provider/types" - ccv "github.com/cosmos/interchain-security/x/ccv/types" + providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" ) var ( @@ -40,30 +34,30 @@ type AppModuleBasic struct{} // Name implements AppModuleBasic interface func (AppModuleBasic) Name() string { - return types.ModuleName + return providertypes.ModuleName } // RegisterLegacyAminoCodec implements AppModuleBasic interface func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - types.RegisterLegacyAminoCodec(cdc) + providertypes.RegisterLegacyAminoCodec(cdc) } // RegisterInterfaces registers module concrete types into protobuf Any. func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { - types.RegisterInterfaces(registry) + providertypes.RegisterInterfaces(registry) } // DefaultGenesis returns default genesis state as raw bytes for the ibc // provider module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return cdc.MustMarshalJSON(types.DefaultGenesisState()) + return cdc.MustMarshalJSON(providertypes.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the ibc provider module. func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - var data types.GenesisState + var data providertypes.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { - return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + return fmt.Errorf("failed to unmarshal %s genesis state: %w", providertypes.ModuleName, err) } return data.Validate() @@ -77,7 +71,7 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc-provider module. // TODO func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { - err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + err := providertypes.RegisterQueryHandlerClient(context.Background(), mux, providertypes.NewQueryClient(clientCtx)) if err != nil { panic(err) } @@ -120,7 +114,7 @@ func (am AppModule) Route() sdk.Route { // QuerierRoute implements the AppModule interface func (AppModule) QuerierRoute() string { - return types.QuerierRoute + return providertypes.QuerierRoute } // LegacyQuerierHandler implements the AppModule interface @@ -131,13 +125,13 @@ func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { // RegisterServices registers module services. // TODO func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + providertypes.RegisterQueryServer(cfg.QueryServer(), am.keeper) } // InitGenesis performs genesis initialization for the provider module. It returns // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { - var genesisState types.GenesisState + var genesisState providertypes.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) am.keeper.InitGenesis(ctx, &genesisState) // initialize validator update id @@ -201,238 +195,3 @@ func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { return nil } - -// ValidateProviderChannelParams does validation of a newly created ccv channel. A provider -// channel must be ORDERED, use the correct port (by default 'provider' on this module), and use the current -// supported version. -func ValidateProviderChannelParams( - ctx sdk.Context, - keeper *keeper.Keeper, - order channeltypes.Order, - portID string, - channelID string, -) error { - if order != channeltypes.ORDERED { - return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.ORDERED, order) - } - - // Require portID is the portID CCV module is bound to - boundPort := keeper.GetPort(ctx) - if boundPort != portID { - return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort) - } - return nil -} - -// OnChanOpenInit implements the IBCModule interface -func (am AppModule) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) error { - return sdkerrors.Wrap(ccv.ErrInvalidChannelFlow, "channel handshake must be initiated by consumer chain") -} - -// OnChanOpenTry implements the IBCModule interface -func (am AppModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (metadata string, err error) { - if err := ValidateProviderChannelParams( - ctx, am.keeper, order, portID, channelID, - ); err != nil { - return "", err - } - - if counterpartyVersion != ccv.Version { - return "", sdkerrors.Wrapf( - ccv.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", - counterpartyVersion, ccv.Version) - } - - // Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos - // (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry) - // If module can already authenticate the capability then module already owns it so we don't need to claim - // Otherwise, module does not have channel capability and we must claim it from IBC - if !am.keeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { - // Only claim channel capability passed back by IBC module if we do not already own it - if err := am.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - } - - if err := am.keeper.VerifyConsumerChain( - ctx, channelID, connectionHops, - ); err != nil { - return "", err - } - - md := types.HandshakeMetadata{ - // NOTE that the fee pool collector address string provided to the - // the consumer chain must be excluded from the blocked addresses - // blacklist or all all ibc-transfers from the consumer chain to the - // provider chain will fail - ProviderFeePoolAddr: am.keeper.GetFeeCollectorAddressStr(ctx), - Version: ccv.Version, - } - mdBz, err := (&md).Marshal() - if err != nil { - return "", sdkerrors.Wrapf(ccv.ErrInvalidHandshakeMetadata, - "error marshalling ibc-try metadata: %v", err) - } - return string(mdBz), nil -} - -// OnChanOpenAck implements the IBCModule interface -func (am AppModule) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyChannelID string, - counterpartyVersion string, -) error { - return sdkerrors.Wrap(ccv.ErrInvalidChannelFlow, "channel handshake must be initiated by consumer chain") -} - -// OnChanOpenConfirm implements the IBCModule interface -func (am AppModule) OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - err := am.keeper.SetConsumerChain(ctx, channelID) - if err != nil { - return err - } - return nil -} - -// OnChanCloseInit implements the IBCModule interface -func (am AppModule) OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // Disallow user-initiated channel closing for provider channels - return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") -} - -// OnChanCloseConfirm implements the IBCModule interface -func (am AppModule) OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - return nil -} - -// OnRecvPacket implements the IBCModule interface. A successful acknowledgement -// is returned if the packet data is succesfully decoded and the receive application -// logic returns without error. -func (am AppModule) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - _ sdk.AccAddress, -) ibcexported.Acknowledgement { - var ( - ack ibcexported.Acknowledgement - vscMaturedData ccv.VSCMaturedPacketData - slashData ccv.SlashPacketData - ) - if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &vscMaturedData); err == nil { - // handle VSCMaturedPacket - ack = am.keeper.OnRecvVSCMaturedPacket(ctx, packet, vscMaturedData) - } else if err := ccv.ModuleCdc.UnmarshalJSON(packet.GetData(), &slashData); err == nil { - // handle SlashPacket - ack = am.keeper.OnRecvSlashPacket(ctx, packet, slashData) - } else { - errAck := channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot unmarshal CCV packet data: %s", err.Error())) - ack = &errAck - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(ccv.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack != nil)), - ), - ) - - return ack -} - -// OnAcknowledgementPacket implements the IBCModule interface -func (am AppModule) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - _ sdk.AccAddress, -) error { - var ack channeltypes.Acknowledgement - if err := ccv.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal provider packet acknowledgement: %v", err) - } - - if err := am.keeper.OnAcknowledgementPacket(ctx, packet, ack); err != nil { - return err - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(ccv.AttributeKeyAck, ack.String()), - ), - ) - - switch resp := ack.Response.(type) { - case *channeltypes.Acknowledgement_Result: - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypePacket, - sdk.NewAttribute(ccv.AttributeKeyAckSuccess, string(resp.Result)), - ), - ) - case *channeltypes.Acknowledgement_Error: - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypePacket, - sdk.NewAttribute(ccv.AttributeKeyAckError, resp.Error), - ), - ) - } - - return nil -} - -// OnTimeoutPacket implements the IBCModule interface -func (am AppModule) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - _ sdk.AccAddress, -) error { - - if err := am.keeper.OnTimeoutPacket(ctx, packet); err != nil { - return err - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - ccv.EventTypeTimeout, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - ) - - return nil -}