From 0f1efaa60cdd7f68ce9e7ff9b56c02acbb3f882e Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Thu, 7 Oct 2021 17:27:12 +0200 Subject: [PATCH 01/10] write handshake docs --- docs/ibc/middleware.md | 172 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 docs/ibc/middleware.md diff --git a/docs/ibc/middleware.md b/docs/ibc/middleware.md new file mode 100644 index 00000000000..98b6d651d1b --- /dev/null +++ b/docs/ibc/middleware.md @@ -0,0 +1,172 @@ + + +# IBC Middleware + +Learn how to write your own custom middleware to wrap an IBC application, and understand how to hook different middleware to IBC base applications to form different IBC application stacks {synopsis}. + +This document serves as a guide for middleware developers who want to write their own middleware and for chain developers who want to use IBC middleware on their chains. + +IBC applications are designed to be self-contained modules that implement their own application-specific logic through a set of interfaces with the core IBC handlers. These core IBC handlers, in turn, are designed to enforce the correctness properties of IBC (transport, authentication, ordering) while delegating all application-specific handling to the IBC application modules. However, there are cases where some functionality may be desired by many applications, yet not appropriate to place in core IBC. + +Middleware allows developers to define the extensions as seperate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. + +## Pre-requisite Readings + +- [IBC Overview](./overview.md)) {prereq} +- [IBC default integration](./integration.md) {prereq} +- [IBC Application Developer Guide](./apps.md) {prereq} + +## Definitions + +`Middleware`: A self-contained module that sits between core IBC and an underlying IBC application during packet execution. All messages between core IBC and underlying application must flow through middleware, which may perform its own custom logic. + +`Underlying Application`: An underlying application is the application that is directly connected to the middleware in question. This underlying application may itself be middleware that is chained to a base application. + +`Base Application`: A base application is an IBC application that does not contain any middleware. It may be nested by 0 or multiple middleware to form an application stack. + +`Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. + +## Create a custom IBC Middleware + +IBC Middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. Thus, middleware must be completely trusted by chain developers who wish to integrate them, however this gives them complete flexibility in modifying the application(s) they wrap. + +Since + +#### Interfaces + +```typescript +// Middleware implements the ICS26 Module interface +interface Middleware extends ICS26Module { + app: ICS26Module // middleware has acccess to an underlying application which may be wrapped by more middleware + ics4Wrapper: ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. +} +``` + +```typescript +// This is implemented by ICS4 and all middleware that are wrapping base application. +// The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them +// which will call the next middleware until it reaches the core IBC handler. +interface ICS4Wrapper { + sendPacket(packet: Packet) + writeAcknowledgement(packet: Packet, ack: Acknowledgement) +} +``` + +### Implement `IBCModule` interface and callbacks + +The middleware must have access to the underlying application, and be called before during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases. + +In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain; they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. + +Middleware accomplishes this by formatting the version in the following format: `{mw-version}:{app-version}`. + +During the handshake callbacks, the middleware can split the version into: `mw-version`, `app-version`. It can do its negotiation logic on `mw-version`, and pass the `app-version` to the underlying application. + +### Handshake Callbacks: + + +```go +func OnChanOpenInit(ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + middlewareVersion, appVersion = splitMiddlewareVersion(version) + doCustomLogic() + app.OnChanOpenInit( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + appVersion, // note we only pass app version here + ) +} + +func OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version, + counterpartyVersion string, +) error { + cpMiddlewareVersion, cpAppVersion = splitMiddlewareVersion(counterpartyVersion) + middlewareVersion, appVersion = splitMiddlewareVersion(version) + if !isCompatible(cpMiddlewareVersion, middlewareVersion) { + return error + } + doCustomLogic() + + // call the underlying applications OnChanOpenTry callback + app.OnChanOpenTry( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + cpAppVersion, // note we only pass counterparty app version here + appVersion, // only pass app version + ) +} + +func OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + middlewareVersion, appVersion = splitMiddlewareVersion(version) + if !isCompatible(middlewareVersion) { + return error + } + doCustomLogic() + + // call the underlying applications OnChanOpenTry callback + app.OnChanOpenAck(ctx, portID, channelID, appVersion) +} + +func OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + doCustomLogic() + + app.OnChanOpenConfirm(ctx, portID, channelID) +} + +OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + doCustomLogic() + + app.OnChanCloseInit(ctx, portID, channelID) +} + +OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + doCustomLogic() + + app.OnChanCloseConfirm(ctx, portID, channelID) +} +``` + From 47f8168699fb65af1625c8988c3b072eb6f058b6 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Fri, 8 Oct 2021 13:31:15 +0200 Subject: [PATCH 02/10] initial docs --- .../{middleware.md => middleware/develop.md} | 62 ++++++++++++++++- docs/ibc/middleware/integration.md | 69 +++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) rename docs/ibc/{middleware.md => middleware/develop.md} (76%) create mode 100644 docs/ibc/middleware/integration.md diff --git a/docs/ibc/middleware.md b/docs/ibc/middleware/develop.md similarity index 76% rename from docs/ibc/middleware.md rename to docs/ibc/middleware/develop.md index 98b6d651d1b..cee0a995610 100644 --- a/docs/ibc/middleware.md +++ b/docs/ibc/middleware/develop.md @@ -1,5 +1,5 @@ # IBC Middleware @@ -170,3 +170,63 @@ OnChanCloseConfirm( } ``` +NOTE: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version splitting and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly. + +### Packet callbacks + +The packet callbacks just like the handshake callbacks wrap the application's packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware. + +```go +OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) ibcexported.Acknowledgement { + doCustomLogic(packet) + + ack := app.OnRecvPacket(ctx, packet) + + doCustomLogic(ack) // middleware may modify outgoing ack + return ack +} + +OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, +) (*sdk.Result, error) { + doCustomLogic(packet, ack) + + app.OnAcknowledgementPacket(ctx, packet, ack) +} + +OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) (*sdk.Result, error) { + doCustomLogic(packet) + + app.OnTimeoutPacket(ctx, packet) +} +``` + +### ICS-4 Wrappers + +Middleware must also wrap ICS-4 so that any communication from the application to the channelKeeper goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes. + +```go +// only called for async acks +func WriteAcknowledgement( + packet channeltypes.Packet, + acknowledgement []bytes) { + // middleware may modify acknowledgement + ack_bytes = doCustomLogic(acknowledgement) + + return ics4Keeper.WriteAcknowledgement(packet, ack_bytes) +} +func SendPacket(appPacket channeltypes.Packet) { + // middleware may modify packet + packet = doCustomLogic(app_packet) + + return ics4Keeper.SendPacket(packet) +} +``` \ No newline at end of file diff --git a/docs/ibc/middleware/integration.md b/docs/ibc/middleware/integration.md new file mode 100644 index 00000000000..2176cff5c73 --- /dev/null +++ b/docs/ibc/middleware/integration.md @@ -0,0 +1,69 @@ + + +# Integrating IBC Middleware into a Chain + +Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for SDK chains. + +If the middleware is maintaining its own state and/or processing SDK messages, then it should create and register its SDK module **only once** with the module manager in `app.go`. + +All middleware must be connected to the IBC router and wrap over an underlying base IBC application. An IBC application may be wrapped by many layers of middleware, only the top layer middleware should be hooked to the IBC router, with all underlying middlewares and application getting wrapped by it. + +The order of middleware **matters**, function calls from IBC to the application travel from top-level middleware to the bottom middleware and then to the application. Function calls from the application to IBC goes through the bottom middleware in order to the top middleware and then to core IBC handlers. Thus the same set of middleware put in different orders may produce different effects. + +### Example integration + +```go +// app.go + +// middleware 1 and middleware 3 are stateful middleware, +// perhaps implementing separate sdk.Msg and Handlers +mw1Keeper := mw1.NewKeeper(storeKey1) +mw3Keeper := mw3.NewKeeper(storeKey3) + +// Only create App Module **once** and register in app module +// if the module maintains independent state and/or processes sdk.Msgs +app.moduleManager = module.NewManager( + ... + mw1.NewAppModule(mw1Keeper), + mw3.NewAppModule(mw3Keeper), + transfer.NewAppModule(transferKeeper), + custom.NewAppModule(customKeeper) +) + +mw1IBCModule := mw1.NewIBCModule(mw1Keeper) +mw2IBCModule := mw2.NewIBCModule() // middleware2 is stateless middleware +mw3IBCModule := mw3.NewIBCModule(mw3Keeper) + +scopedKeeperTransfer := capabilityKeeper.NewScopedKeeper("transfer") +scopedKeeperCustom1 := capabilityKeeper.NewScopedKeeper("custom1") +scopedKeeperCustom2 := capabilityKeeper.NewScopedKeeper("custom2") + +// NOTE: IBC Modules may be initialized any number of times provided they use a separate +// scopedKeeper and underlying port. + +// initialize base IBC applications +// if you want to create two different stacks with the same base application, +// they must be given different scopedKeepers and assigned different ports. +transferIBCModule := transfer.NewIBCModule(transferKeeper, scopedKeeperTransfer) +customIBCModule1 := custom.NewIBCModule(customKeeper, scopedKeeperCustom1, "portCustom1") +customIBCModule2 := custom.NewIBCModule(customKeeper, scopedKeeperCustom2, "portCustom2") + +// create IBC stacks by combining middleware with base application +// NOTE: since middleware2 is stateless it does not require a Keeper +// stack 1 contains mw1 -> mw3 -> transfer +stack1 := mw1.NewIBCModule(mw1Keeper, mw3.NewIBCModule(mw3Keeper, transferIBCModule)) +// stack 2 contains mw3 -> mw2 -> custom1 +stack2 := mw3.NewIBCModule(mw3Keeper, mw3.NewIBCModule(customIBCModule1)) +// stack 3 contains mw2 -> mw1 -> custom2 +stack3 := mw2.NewIBCModule(mw1.NewIBCModule(mw1Keeper, customIBCModule2)) + +// associate each stack with the moduleName provided by the underlying scopedKeeper +ibcRouter := porttypes.NewRouter() +ibcRouter.AddRoute("transfer", stack1) +ibcRouter.AddRoute("custom1", stack2) +ibcRouter.AddRoute("custom2", stack3) +app.IBCKeeper.SetRouter(ibcRouter) +``` + From 7ed7039f015f5bbbd9b3493ffef325ebcac5e2f2 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Fri, 8 Oct 2021 13:55:18 +0200 Subject: [PATCH 03/10] fix links --- docs/ibc/middleware/develop.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index cee0a995610..e8016c57bc6 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -14,9 +14,9 @@ Middleware allows developers to define the extensions as seperate modules that c ## Pre-requisite Readings -- [IBC Overview](./overview.md)) {prereq} -- [IBC default integration](./integration.md) {prereq} -- [IBC Application Developer Guide](./apps.md) {prereq} +- [IBC Overview](../overview.md) {prereq} +- [IBC default integration](../integration.md) {prereq} +- [IBC Application Developer Guide](../apps.md) {prereq} ## Definitions From bbf555d8a0144e09b86395ba183f7aec8d0355c1 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Mon, 11 Oct 2021 11:09:42 +0200 Subject: [PATCH 04/10] remove since --- docs/ibc/middleware/develop.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index e8016c57bc6..e101ad47096 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -32,8 +32,6 @@ Middleware allows developers to define the extensions as seperate modules that c IBC Middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. Thus, middleware must be completely trusted by chain developers who wish to integrate them, however this gives them complete flexibility in modifying the application(s) they wrap. -Since - #### Interfaces ```typescript From 534e4c5f374df3e749767890970fb86a5fbe026d Mon Sep 17 00:00:00 2001 From: Aditya Date: Mon, 11 Oct 2021 11:15:21 +0200 Subject: [PATCH 05/10] Update docs/ibc/middleware/integration.md Co-authored-by: Damian Nolan --- docs/ibc/middleware/integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ibc/middleware/integration.md b/docs/ibc/middleware/integration.md index 2176cff5c73..68a8de00899 100644 --- a/docs/ibc/middleware/integration.md +++ b/docs/ibc/middleware/integration.md @@ -4,7 +4,7 @@ order: 2 # Integrating IBC Middleware into a Chain -Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for SDK chains. +Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for Cosmos SDK chains. If the middleware is maintaining its own state and/or processing SDK messages, then it should create and register its SDK module **only once** with the module manager in `app.go`. From 6f83e8df2ff226d83f0a7daafb33a1d48a99d630 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 14 Oct 2021 12:37:16 +0200 Subject: [PATCH 06/10] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- docs/ibc/middleware/develop.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index e101ad47096..1c83e113748 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -15,7 +15,7 @@ Middleware allows developers to define the extensions as seperate modules that c ## Pre-requisite Readings - [IBC Overview](../overview.md) {prereq} -- [IBC default integration](../integration.md) {prereq} +- [IBC Integration](../integration.md) {prereq} - [IBC Application Developer Guide](../apps.md) {prereq} ## Definitions @@ -66,7 +66,7 @@ During the handshake callbacks, the middleware can split the version into: `mw-v ```go -func OnChanOpenInit(ctx sdk.Context, +func (im IBCModule) OnChanOpenInit(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, @@ -77,7 +77,7 @@ func OnChanOpenInit(ctx sdk.Context, ) error { middlewareVersion, appVersion = splitMiddlewareVersion(version) doCustomLogic() - app.OnChanOpenInit( + im.app.OnChanOpenInit( ctx, order, connectionHops, From ea7775127e435c09a125ace42747f75086638d90 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Thu, 14 Oct 2021 12:59:50 +0200 Subject: [PATCH 07/10] address suggestions --- docs/ibc/middleware/develop.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 1c83e113748..8f83c60060a 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -10,7 +10,7 @@ This document serves as a guide for middleware developers who want to write thei IBC applications are designed to be self-contained modules that implement their own application-specific logic through a set of interfaces with the core IBC handlers. These core IBC handlers, in turn, are designed to enforce the correctness properties of IBC (transport, authentication, ordering) while delegating all application-specific handling to the IBC application modules. However, there are cases where some functionality may be desired by many applications, yet not appropriate to place in core IBC. -Middleware allows developers to define the extensions as seperate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. +Middleware allows developers to define the extensions as separate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. ## Pre-requisite Readings @@ -34,10 +34,10 @@ IBC Middleware will wrap over an underlying IBC application and sits between cor #### Interfaces -```typescript +```go // Middleware implements the ICS26 Module interface -interface Middleware extends ICS26Module { - app: ICS26Module // middleware has acccess to an underlying application which may be wrapped by more middleware +type Middleware interface { + porttypes.Module // middleware has acccess to an underlying application which may be wrapped by more middleware ics4Wrapper: ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. } ``` @@ -46,14 +46,16 @@ interface Middleware extends ICS26Module { // This is implemented by ICS4 and all middleware that are wrapping base application. // The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them // which will call the next middleware until it reaches the core IBC handler. -interface ICS4Wrapper { - sendPacket(packet: Packet) - writeAcknowledgement(packet: Packet, ack: Acknowledgement) +type ICS4Wrapper interface { + SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet) error + WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet, ack []byte) error } ``` ### Implement `IBCModule` interface and callbacks +The IBCModule is struct that implements the ICS26Interface (`porttypes.Module`). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration doc](./integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. + The middleware must have access to the underlying application, and be called before during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases. In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain; they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. @@ -75,7 +77,8 @@ func (im IBCModule) OnChanOpenInit(ctx sdk.Context, counterparty channeltypes.Counterparty, version string, ) error { - middlewareVersion, appVersion = splitMiddlewareVersion(version) + // core/04-channel/types contains a helper function to split middleware and underlying app version + middlewareVersion, appVersion = channeltypes.SplitChannelVersion(version) doCustomLogic() im.app.OnChanOpenInit( ctx, @@ -100,8 +103,9 @@ func OnChanOpenTry( version, counterpartyVersion string, ) error { - cpMiddlewareVersion, cpAppVersion = splitMiddlewareVersion(counterpartyVersion) - middlewareVersion, appVersion = splitMiddlewareVersion(version) + // core/04-channel/types contains a helper function to split middleware and underlying app version + cpMiddlewareVersion, cpAppVersion = channeltypes.SplitChannelVersion(counterpartyVersion) + middlewareVersion, appVersion = channeltypes.SplitChannelVersion(version) if !isCompatible(cpMiddlewareVersion, middlewareVersion) { return error } @@ -127,7 +131,8 @@ func OnChanOpenAck( channelID string, counterpartyVersion string, ) error { - middlewareVersion, appVersion = splitMiddlewareVersion(version) + // core/04-channel/types contains a helper function to split middleware and underlying app version + middlewareVersion, appVersion = channeltypes.SplitChannelVersion(version) if !isCompatible(middlewareVersion) { return error } @@ -221,6 +226,7 @@ func WriteAcknowledgement( return ics4Keeper.WriteAcknowledgement(packet, ack_bytes) } + func SendPacket(appPacket channeltypes.Packet) { // middleware may modify packet packet = doCustomLogic(app_packet) From 2272db50e4d2999b16eb86273e8b1cfe915458c8 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Thu, 14 Oct 2021 13:28:02 +0200 Subject: [PATCH 08/10] add in-code interfaces and clarify cap docs --- docs/ibc/middleware/develop.md | 4 ++++ modules/core/04-channel/keeper/keeper.go | 2 ++ modules/core/05-port/types/module.go | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 8f83c60060a..0c9f6d1a171 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -64,6 +64,10 @@ Middleware accomplishes this by formatting the version in the following format: During the handshake callbacks, the middleware can split the version into: `mw-version`, `app-version`. It can do its negotiation logic on `mw-version`, and pass the `app-version` to the underlying application. +The middleware should simply pass the capability in the callback arguments along to the underlying application so that it may be claimed by the base application. The base application will then pass the capability up the stack in order to authenticate an outgoing packet/acknowledgement. + +In the case where the middleware wishes to send a packet or acknowledgment without the involvement of the underlying application, it should be given access to the same `scopedKeeper` as the base application so that it can retrieve the capabilities by itself. + ### Handshake Callbacks: diff --git a/modules/core/04-channel/keeper/keeper.go b/modules/core/04-channel/keeper/keeper.go index c5e07148c78..cb8201ce585 100644 --- a/modules/core/04-channel/keeper/keeper.go +++ b/modules/core/04-channel/keeper/keeper.go @@ -20,6 +20,8 @@ import ( "github.com/cosmos/ibc-go/v2/modules/core/exported" ) +var _ porttypes.ICS4Wrapper = Keeper{} + // Keeper defines the IBC channel keeper type Keeper struct { // implements gRPC QueryServer interface diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 8e4bd092f67..6f66c72a530 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -95,3 +95,26 @@ type IBCModule interface { proposedVersion string, ) (version string, err error) } + +// ICS4Wrapper implements the ICS4 interfaces that IBC applications use to send packets and acknolwedgements. +type ICS4Wrapper interface { + SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + ) error + + WriteAcknowledgement( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + ack []byte, + ) error +} + +// Middleware must implement IBCModule to wrap communication from core IBC to underlying application +// and ICS4Wrapper to wrap communication from underlying application to core IBC. +type Middleware interface { + IBCModule + ICS4Wrapper +} From 2e91118705875ec4da2fa60e977ab87a9c4d714b Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Thu, 14 Oct 2021 13:30:58 +0200 Subject: [PATCH 09/10] fix carlos nit --- docs/ibc/middleware/develop.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 0c9f6d1a171..c52037826a2 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -68,8 +68,7 @@ The middleware should simply pass the capability in the callback arguments along In the case where the middleware wishes to send a packet or acknowledgment without the involvement of the underlying application, it should be given access to the same `scopedKeeper` as the base application so that it can retrieve the capabilities by itself. -### Handshake Callbacks: - +### Handshake callbacks ```go func (im IBCModule) OnChanOpenInit(ctx sdk.Context, From 153e8748f7dcb30639d85fc20feefbd6dd010c3b Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Thu, 14 Oct 2021 13:31:48 +0200 Subject: [PATCH 10/10] Module -> IBCModule --- docs/ibc/middleware/develop.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index c52037826a2..b4cd037e5e6 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -37,7 +37,7 @@ IBC Middleware will wrap over an underlying IBC application and sits between cor ```go // Middleware implements the ICS26 Module interface type Middleware interface { - porttypes.Module // middleware has acccess to an underlying application which may be wrapped by more middleware + porttypes.IBCModule // middleware has acccess to an underlying application which may be wrapped by more middleware ics4Wrapper: ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. } ``` @@ -54,7 +54,7 @@ type ICS4Wrapper interface { ### Implement `IBCModule` interface and callbacks -The IBCModule is struct that implements the ICS26Interface (`porttypes.Module`). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration doc](./integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. +The IBCModule is struct that implements the ICS26Interface (`porttypes.IBCModule`). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration doc](./integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. The middleware must have access to the underlying application, and be called before during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases.