本指南提供了迁移到 ibc-go 新版本的说明。 注意: ibc-go 遵循 golang 语义化版本控制,因此在主版本发布时,所有导入都必须更新。此外,在这个版本中,08-wasm 模块已作为 v10 发布,callbacks 中间件也已移动到 ibc-go 模块本身中。 以下是整体变更列表,后面附有差异示例:
  • 为了添加对 IBC v2 的支持,链需要接入一个新的 IBC v2 Transfer 栈
  • 链需要接入新的轻客户端模块
  • 链需要更新 Keeper 构造调用,以符合新的函数签名
  • 链需要从其 app/app.go 中移除 02-client 旧版 proposal handler 的路由
  • 链需要从其 app/app.go 中移除 capability keeper 及所有相关设置,包括 scoped keepers
  • 链需要移除 ibc fee 中间件(29-fee)
  • 如果使用该模块,链需要将 github.com/cosmos/ibc-go/modules/light-clients/08-wasm/ 的导入和用法更新为 github.com/cosmos/ibc-go/modules/light-clients/08-wasm/v10
  • 如果使用该模块,链需要将 github.com/cosmos/ibc-go/modules/apps/callbacks 的导入和用法更新为 github.com/cosmos/ibc-go/v10/modules/apps/callbacks
要添加 IBC v2 支持,请接入一个新的 transfer 栈。下面的示例展示了如何与 IBC Callbacks 模块一起接入:
+ var ibcv2TransferStack ibcapi.IBCModule
+ ibcv2TransferStack = transferv2.NewIBCModule(app.TransferKeeper)
+ ibcv2TransferStack = ibccallbacksv2.NewIBCMiddleware(
+   transferv2.NewIBCModule(app.TransferKeeper),
+   app.IBCKeeper.ChannelKeeperV2,
+   wasmStackIBCHandler,
+   app.IBCKeeper.ChannelKeeperV2,
+   maxCallbackGas,
+ )
将每个轻客户端作为单独模块接入,并将它们添加到 client keeper router 中。下面是 07-tendermint 和 08-wasm 的示例:
+ / Light client modules
+ clientKeeper := app.IBCKeeper.ClientKeeper
+ storeProvider := app.IBCKeeper.ClientKeeper.GetStoreProvider()
+
+ tmLightClientModule := ibctm.NewLightClientModule(appCodec, storeProvider)
+ clientKeeper.AddRoute(ibctm.ModuleName, &tmLightClientModule)
+
+ wasmLightClientModule := ibcwasm.NewLightClientModule(app.WasmClientKeeper, storeProvider)
+ clientKeeper.AddRoute(ibcwasmtypes.ModuleName, &wasmLightClientModule)
从模块账户权限中移除 ibc fee 模块名(如果使用了该模块):
  / app.go
  ...
  / module account permissions
  var maccPerms = map[string][]string{
    ...
-   ibcfeetypes.ModuleName:      nil,
    ...
  }
从 App 结构体中移除 CapabilityKeeper、IBCFeeKeeper 以及所有 capabilitykeeper.ScopedKeeper 类型的 Scoped keepers:
  / ChainApp extended ABCI application
  type ChainApp struct {
    ...
-	CapabilityKeeper      *capabilitykeeper.Keeper
    ...
-   IBCFeeKeeper        ibcfeekeeper.Keeper
    ...
-   ScopedIBCKeeper           capabilitykeeper.ScopedKeeper
-	ScopedICAHostKeeper       capabilitykeeper.ScopedKeeper
-	ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper
-	ScopedTransferKeeper      capabilitykeeper.ScopedKeeper
-	ScopedIBCFeeKeeper        capabilitykeeper.ScopedKeeper
    ...
  }
  ...
- app.ScopedIBCKeeper = scopedIBCKeeper
- app.ScopedTransferKeeper = scopedTransferKeeper
- app.ScopedWasmKeeper = scopedWasmKeeper
- app.ScopedICAHostKeeper = scopedICAHostKeeper
- app.ScopedICAControllerKeeper = scopedICAControllerKeeper
从 NewKVStoreKeys 调用中移除 capability 和 ibc fee 中间件的 store key:
...
  keys := storetypes.NewKVStoreKeys(
    ...
-   capabilitytypes.StoreKey,
-   ibcfeetypes.StoreKey,
    ...
  }
移除之前由 capability 模块使用的内存 store key:
- memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
...
- app.MountMemoryStores(memKeys)
移除 capability keeper 的创建:
- / add capability keeper and ScopeToModule for ibc module
- 	app.CapabilityKeeper = capabilitykeeper.NewKeeper(
- 		appCodec,
- 		keys[capabilitytypes.StoreKey],
- 		memKeys[capabilitytypes.MemStoreKey],
- 	)

- 	scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName)
- 	scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName)
- 	scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName)
- 	scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName)
- 	scopedWasmKeeper := app.CapabilityKeeper.ScopeToModule(wasmtypes.ModuleName)
- 	app.CapabilityKeeper.Seal()
移除 client keeper 的旧版路由:
...
  govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
- AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
- AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper))
+ AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper))
更新 Core IBC Keeper 构造函数:
  app.IBCKeeper = ibckeeper.NewKeeper(
	appCodec,
-	keys[ibcexported.StoreKey],
+	runtime.NewKVStoreService(keys[ibcexported.StoreKey]),
	app.GetSubspace(ibcexported.ModuleName),
-	app.StakingKeeper,
	app.UpgradeKeeper,
-	scopedIBCKeeper,
	authtypes.NewModuleAddress(govtypes.ModuleName).String(),
  )
更新 IBC Transfer keeper 构造函数:
  app.TransferKeeper = ibctransferkeeper.NewKeeper(
	appCodec,
-	keys[ibctransfertypes.StoreKey],
+	runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]),
	app.GetSubspace(ibctransfertypes.ModuleName),
	app.IBCKeeper.ChannelKeeper,
	app.IBCKeeper.ChannelKeeper,
-	app.IBCKeeper.PortKeeper,
+	app.MsgServiceRouter(),
	app.AccountKeeper,
	app.BankKeeper,
-	scopedTransferKeeper,
	authtypes.NewModuleAddress(govtypes.ModuleName).String(),
  )
更新 ICA Host keeper 构造函数,特别注意其中移除了 WithQueryRouter 调用:
  app.ICAHostKeeper = icahostkeeper.NewKeeper(
	appCodec,
-	keys[icahosttypes.StoreKey],
+	runtime.NewKVStoreService(keys[icahosttypes.StoreKey]),
	app.GetSubspace(icahosttypes.SubModuleName),
-	app.IBCFeeKeeper, / use ics29 fee as ics4Wrapper in middleware stack
	app.IBCKeeper.ChannelKeeper,
-	app.IBCKeeper.PortKeeper,
+	app.IBCKeeper.ChannelKeeper,
	app.AccountKeeper,
-	scopedICAHostKeeper,
	app.MsgServiceRouter(),
+	app.GRPCQueryRouter(),
	authtypes.NewModuleAddress(govtypes.ModuleName).String(),
  )
- app.ICAHostKeeper.WithQueryRouter(app.GRPCQueryRouter())
移除 IBC Fee Module keeper:
- app.IBCFeeKeeper = ibcfeekeeper.NewKeeper(
-	appCodec, keys[ibcfeetypes.StoreKey],
-	app.IBCKeeper.ChannelKeeper, / may be replaced with IBC middleware
-	app.IBCKeeper.ChannelKeeper,
-	app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper,
- )
更新 Transfer 栈以移除 fee 中间件。下面的示例展示了在使用 IBC callbacks 中间件时,正确接入中间件栈的方式:
  / Create Transfer Stack
  var transferStack porttypes.IBCModule
  transferStack = transfer.NewIBCModule(app.TransferKeeper)
- transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, wasmStackIBCHandler, maxCallbackGas)
- transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper)
+ / callbacks wraps the transfer stack as its base app, and uses PacketForwardKeeper as the ICS4Wrapper
+ / i.e. packet-forward-middleware is higher on the stack and sits between callbacks and the ibc channel keeper
+ / Since this is the lowest level middleware of the transfer stack, it should be the first entrypoint for transfer keeper's
+ / WriteAcknowledgement.
+ cbStack := ibccallbacks.NewIBCMiddleware(transferStack, app.PacketForwardKeeper, wasmStackIBCHandler, maxCallbackGas)
transferStack = packetforward.NewIBCMiddleware(
-	transferStack,
+	cbStack,
	app.PacketForwardKeeper,
	0,
	packetforwardkeeper.DefaultForwardTransferPacketTimeoutTimestamp,
  )
+ app.TransferKeeper.WithICS4Wrapper(cbStack)
在创建 ICA Controller 栈时,移除 ibc fee 中间件以及任何空的 IBCModule(通常称为 noAuthzModule):
- var noAuthzModule porttypes.IBCModule
- icaControllerStack = icacontroller.NewIBCMiddleware(noAuthzModule, app.ICAControllerKeeper)
- icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper)
+ icaControllerStack = icacontroller.NewIBCMiddleware(app.ICAControllerKeeper)
从 ICA Host 栈创建中移除 ibc fee 中间件:
  icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper)
- icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper)
更新 module manager 的创建,移除 capability 模块和 fee 模块,并更新 tendermint app module 构造函数:
  app.ModuleManager = module.NewManager(
    ...
-   capability.NewAppModule(appCodec, *app.CapabilityKeeper, false),
    ...
-   ibcfee.NewAppModule(app.IBCFeeKeeper),
    ...
-   ibctm.NewAppModule(),
+   ibctm.NewAppModule(tmLightClientModule),
    ...
  )
从 SetOrderBeginBlockers、SetOrderEndBlockers、SetOrderInitGenesis 和 SetOrderExportGenesis 中移除 capability 模块和 ibc fee 中间件:
-   capabilitytypes.ModuleName,
-   ibcfeetypes.ModuleName,
如果你使用 08-wasm,则需要更新用于 QueryPlugins 和 AcceptListStargateQuerier 的 go module:
- wasmLightClientQuerier := ibcwasmtypes.QueryPlugins{
+ wasmLightClientQuerier := ibcwasmkeeper.QueryPlugins{
-	Stargate: ibcwasmtypes.AcceptListStargateQuerier([]string{
+	Stargate: ibcwasmkeeper.AcceptListStargateQuerier([]string{
		"/ibc.core.client.v1.Query/ClientState",
		"/ibc.core.client.v1.Query/ConsensusState",
		"/ibc.core.connection.v1.Query/Connection",
-	}),
+	}, app.GRPCQueryRouter()),
  }
如果你使用 08-wasm,则需要使用 wasm client keeper,而不是 go module,来初始化 pinned codes:
- if err := ibcwasmkeeper.InitializePinnedCodes(ctx); err != nil {
-	panic(fmt.Sprintf("ibcwasmkeeper failed initialize pinned codes %s", err))
+ if err := app.WasmClientKeeper.InitializePinnedCodes(ctx); err != nil {
+	panic(fmt.Sprintf("WasmClientKeeper failed initialize pinned codes %s", err))
+ }

This guide provides instructions for migrating to a new version of ibc-go. Note: ibc-go supports golang semantic versioning and therefore all imports must be updated on major version releases. In addition, for this release, the 08-wasm module has been released as v10, and the callbacks middleware has been moved into the ibc-go module itself. Diff examples are shown after the list of overall changes:
  • To add support for IBC v2, Chains will need to wire up a new IBC v2 Transfer stack
  • Chains will need to wire up the new light client modules
  • Chains will need to update Keeper construction calls to comply with the new signatures
  • Chains will need to remove the route for the legacy proposal handler for 02-client from their app/app.go
  • Chains will need to remove the capability keeper and all related setup, including the scoped keepers from their app/app.go
  • Chains will need to remove ibc fee middleware (29-fee)
  • Chains will need, if using this module, to update their imports and usage of github.com/cosmos/ibc-go/modules/light-clients/08-wasm/ to github.com/cosmos/ibc-go/modules/light-clients/08-wasm/v10
  • Chains will need, if using this module, to update their imports and usage of github.com/cosmos/ibc-go/modules/apps/callbacks to github.com/cosmos/ibc-go/v10/modules/apps/callbacks
To add IBC v2 support, wire up a new transfer stack. Example below showing wired up with IBC Callbacks module:
+ var ibcv2TransferStack ibcapi.IBCModule
+ ibcv2TransferStack = transferv2.NewIBCModule(app.TransferKeeper)
+ ibcv2TransferStack = ibccallbacksv2.NewIBCMiddleware(
+   transferv2.NewIBCModule(app.TransferKeeper),
+   app.IBCKeeper.ChannelKeeperV2,
+   wasmStackIBCHandler,
+   app.IBCKeeper.ChannelKeeperV2,
+   maxCallbackGas,
+ )
Wire up each light client as a separate module and add them to the client keeper router. Example below for 07-tendermint and 08-wasm:
+ / Light client modules
+ clientKeeper := app.IBCKeeper.ClientKeeper
+ storeProvider := app.IBCKeeper.ClientKeeper.GetStoreProvider()
+
+ tmLightClientModule := ibctm.NewLightClientModule(appCodec, storeProvider)
+ clientKeeper.AddRoute(ibctm.ModuleName, &tmLightClientModule)
+
+ wasmLightClientModule := ibcwasm.NewLightClientModule(app.WasmClientKeeper, storeProvider)
+ clientKeeper.AddRoute(ibcwasmtypes.ModuleName, &wasmLightClientModule)
Remove ibc fee module name (if used) from module account permissions:
  / app.go
  ...
  / module account permissions
  var maccPerms = map[string][]string{
    ...
-   ibcfeetypes.ModuleName:      nil,
    ...
  }
Remove CapabilityKeeper, IBCFeeKeeper and all capabilitykeeper.ScopedKeeper Scoped keepers from the App struct:
  / ChainApp extended ABCI application
  type ChainApp struct {
    ...
-	CapabilityKeeper      *capabilitykeeper.Keeper
    ...
-   IBCFeeKeeper        ibcfeekeeper.Keeper
    ...
-   ScopedIBCKeeper           capabilitykeeper.ScopedKeeper
-	ScopedICAHostKeeper       capabilitykeeper.ScopedKeeper
-	ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper
-	ScopedTransferKeeper      capabilitykeeper.ScopedKeeper
-	ScopedIBCFeeKeeper        capabilitykeeper.ScopedKeeper
    ...
  }
  ...
- app.ScopedIBCKeeper = scopedIBCKeeper
- app.ScopedTransferKeeper = scopedTransferKeeper
- app.ScopedWasmKeeper = scopedWasmKeeper
- app.ScopedICAHostKeeper = scopedICAHostKeeper
- app.ScopedICAControllerKeeper = scopedICAControllerKeeper
Remove capability and ibc fee middleware store keys from the NewKVStoreKeys call:
...
  keys := storetypes.NewKVStoreKeys(
    ...
-   capabilitytypes.StoreKey,
-   ibcfeetypes.StoreKey,
    ...
  }
Remove the in-memory store keys previously used by the capability module:
- memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
...
- app.MountMemoryStores(memKeys)
Remove creation of the capability keeper:
- / add capability keeper and ScopeToModule for ibc module
- 	app.CapabilityKeeper = capabilitykeeper.NewKeeper(
- 		appCodec,
- 		keys[capabilitytypes.StoreKey],
- 		memKeys[capabilitytypes.MemStoreKey],
- 	)

- 	scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName)
- 	scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName)
- 	scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName)
- 	scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName)
- 	scopedWasmKeeper := app.CapabilityKeeper.ScopeToModule(wasmtypes.ModuleName)
- 	app.CapabilityKeeper.Seal()
Remove the legacy route for the client keeper:
...
  govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
- AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
- AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper))
+ AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper))
Update Core IBC Keeper constructor:
  app.IBCKeeper = ibckeeper.NewKeeper(
	appCodec,
-	keys[ibcexported.StoreKey],
+	runtime.NewKVStoreService(keys[ibcexported.StoreKey]),
	app.GetSubspace(ibcexported.ModuleName),
-	app.StakingKeeper,
	app.UpgradeKeeper,
-	scopedIBCKeeper,
	authtypes.NewModuleAddress(govtypes.ModuleName).String(),
  )
Update IBC Transfer keeper constructor:
  app.TransferKeeper = ibctransferkeeper.NewKeeper(
	appCodec,
-	keys[ibctransfertypes.StoreKey],
+	runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]),
	app.GetSubspace(ibctransfertypes.ModuleName),
	app.IBCKeeper.ChannelKeeper,
	app.IBCKeeper.ChannelKeeper,
-	app.IBCKeeper.PortKeeper,
+	app.MsgServiceRouter(),
	app.AccountKeeper,
	app.BankKeeper,
-	scopedTransferKeeper,
	authtypes.NewModuleAddress(govtypes.ModuleName).String(),
  )
Update ICA Host keeper constructor, notice the removal of the WithQueryRouter call in particular:
  app.ICAHostKeeper = icahostkeeper.NewKeeper(
	appCodec,
-	keys[icahosttypes.StoreKey],
+	runtime.NewKVStoreService(keys[icahosttypes.StoreKey]),
	app.GetSubspace(icahosttypes.SubModuleName),
-	app.IBCFeeKeeper, / use ics29 fee as ics4Wrapper in middleware stack
	app.IBCKeeper.ChannelKeeper,
-	app.IBCKeeper.PortKeeper,
+	app.IBCKeeper.ChannelKeeper,
	app.AccountKeeper,
-	scopedICAHostKeeper,
	app.MsgServiceRouter(),
+	app.GRPCQueryRouter(),
	authtypes.NewModuleAddress(govtypes.ModuleName).String(),
  )
- app.ICAHostKeeper.WithQueryRouter(app.GRPCQueryRouter())
Remove IBC Fee Module keeper:
- app.IBCFeeKeeper = ibcfeekeeper.NewKeeper(
-	appCodec, keys[ibcfeetypes.StoreKey],
-	app.IBCKeeper.ChannelKeeper, / may be replaced with IBC middleware
-	app.IBCKeeper.ChannelKeeper,
-	app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper,
- )
Update Transfer stack to remove the fee middleware. The example below shows the correct way to wire up a middleware stack with the IBC callbacks middleware:
  / Create Transfer Stack
  var transferStack porttypes.IBCModule
  transferStack = transfer.NewIBCModule(app.TransferKeeper)
- transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, wasmStackIBCHandler, maxCallbackGas)
- transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper)
+ / callbacks wraps the transfer stack as its base app, and uses PacketForwardKeeper as the ICS4Wrapper
+ / i.e. packet-forward-middleware is higher on the stack and sits between callbacks and the ibc channel keeper
+ / Since this is the lowest level middleware of the transfer stack, it should be the first entrypoint for transfer keeper's
+ / WriteAcknowledgement.
+ cbStack := ibccallbacks.NewIBCMiddleware(transferStack, app.PacketForwardKeeper, wasmStackIBCHandler, maxCallbackGas)
transferStack = packetforward.NewIBCMiddleware(
-	transferStack,
+	cbStack,
	app.PacketForwardKeeper,
	0,
	packetforwardkeeper.DefaultForwardTransferPacketTimeoutTimestamp,
  )
+ app.TransferKeeper.WithICS4Wrapper(cbStack)
Remove ibc fee middleware and any empty IBCModule (often dubbed noAuthzModule) from the ICA Controller stack creation:
- var noAuthzModule porttypes.IBCModule
- icaControllerStack = icacontroller.NewIBCMiddleware(noAuthzModule, app.ICAControllerKeeper)
- icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper)
+ icaControllerStack = icacontroller.NewIBCMiddleware(app.ICAControllerKeeper)
Remove ibc fee middleware from ICA Host stack creation:
  icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper)
- icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper)
Update the module manager creation by removing the capability module, fee module and updating the tendermint app module constructor:
  app.ModuleManager = module.NewManager(
    ...
-   capability.NewAppModule(appCodec, *app.CapabilityKeeper, false),
    ...
-   ibcfee.NewAppModule(app.IBCFeeKeeper),
    ...
-   ibctm.NewAppModule(),
+   ibctm.NewAppModule(tmLightClientModule),
    ...
  )
Remove the capability module and ibc fee middleware from SetOrderBeginBlockers, SetOrderEndBlockers, SetOrderInitGenesis and SetOrderExportGenesis:
-   capabilitytypes.ModuleName,
-   ibcfeetypes.ModuleName,
If you use 08-wasm, you will need to update the go module that is used for QueryPlugins and AcceptListStargateQuerier.
- wasmLightClientQuerier := ibcwasmtypes.QueryPlugins{
+ wasmLightClientQuerier := ibcwasmkeeper.QueryPlugins{
-	Stargate: ibcwasmtypes.AcceptListStargateQuerier([]string{
+	Stargate: ibcwasmkeeper.AcceptListStargateQuerier([]string{
		"/ibc.core.client.v1.Query/ClientState",
		"/ibc.core.client.v1.Query/ConsensusState",
		"/ibc.core.connection.v1.Query/Connection",
-	}),
+	}, app.GRPCQueryRouter()),
  }
If you use 08-wasm, you will need to use the wasm client keeper rather than the go module to initialize pinned codes:
- if err := ibcwasmkeeper.InitializePinnedCodes(ctx); err != nil {
-	panic(fmt.Sprintf("ibcwasmkeeper failed initialize pinned codes %s", err))
+ if err := app.WasmClientKeeper.InitializePinnedCodes(ctx); err != nil {
+	panic(fmt.Sprintf("WasmClientKeeper failed initialize pinned codes %s", err))
+ }